fix memory mcp
This commit is contained in:
parent
2f27e10f62
commit
df128e5048
@ -60,18 +60,19 @@ def call_mcp(cfg, message: str):
|
|||||||
return response.json().get("output", {}).get("response", "❓ 応答が取得できませんでした")
|
return response.json().get("output", {}).get("response", "❓ 応答が取得できませんでした")
|
||||||
|
|
||||||
def call_openai(cfg, message: str):
|
def call_openai(cfg, message: str):
|
||||||
|
# ツール定義
|
||||||
tools = [
|
tools = [
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "memory", # MCPツール名と一致させる
|
"name": "memory",
|
||||||
"description": "AIが記憶ログを参照するツールです",
|
"description": "記憶を検索する",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"query": {
|
"query": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "探している記憶に関するキーワードや質問"
|
"description": "検索する語句"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["query"]
|
"required": ["query"]
|
||||||
@ -80,15 +81,15 @@ def call_openai(cfg, message: str):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# 最初のメッセージ送信
|
||||||
payload = {
|
payload = {
|
||||||
"model": cfg["model"],
|
"model": cfg["model"],
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "system", "content": "あなたはAIで、必要に応じて記憶検索ツール(memory)を使って過去の会話を参照することができます。"},
|
{"role": "system", "content": "あなたはAIで、必要に応じてツールmemoryを使って記憶を検索します。"},
|
||||||
{"role": "user", "content": message}
|
{"role": "user", "content": message}
|
||||||
],
|
],
|
||||||
"temperature": 0.7,
|
"tools": tools,
|
||||||
"tool_choice": "auto", # AIが自律的にツールを選ぶ
|
"tool_choice": "auto"
|
||||||
"tools": tools
|
|
||||||
}
|
}
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
@ -96,25 +97,43 @@ def call_openai(cfg, message: str):
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
|
||||||
response = requests.post(cfg["url"], headers=headers, json=payload)
|
res1 = requests.post(cfg["url"], headers=headers, json=payload)
|
||||||
response.raise_for_status()
|
res1.raise_for_status()
|
||||||
|
result = res1.json()
|
||||||
|
|
||||||
result = response.json()
|
# 🧠 tool_call されたか確認
|
||||||
|
|
||||||
# AIがtool_callしたかチェック
|
|
||||||
if "tool_calls" in result["choices"][0]["message"]:
|
if "tool_calls" in result["choices"][0]["message"]:
|
||||||
tool_call = result["choices"][0]["message"]["tool_calls"][0]
|
tool_call = result["choices"][0]["message"]["tool_calls"][0]
|
||||||
if tool_call["function"]["name"] == "memory":
|
if tool_call["function"]["name"] == "memory":
|
||||||
args = json.loads(tool_call["function"]["arguments"])
|
args = json.loads(tool_call["function"]["arguments"])
|
||||||
query = args.get("query", "")
|
query = args.get("query", "")
|
||||||
# ここでMCP serverにPOSTする
|
print(f"🛠️ ツール実行: memory(query='{query}')")
|
||||||
memory_response = requests.post(
|
|
||||||
"http://127.0.0.1:5000/memory/search", # あらかじめ実装されたmemory検索用API
|
# MCPエンドポイントにPOST
|
||||||
json={"query": query}
|
memory_res = requests.post("http://127.0.0.1:5000/memory/search", json={"query": query})
|
||||||
).json()
|
memory_json = memory_res.json()
|
||||||
return f"[Memory Tool]: {memory_response.get('result', 'なし')}"
|
tool_output = memory_json.get("result", "なし")
|
||||||
|
|
||||||
# 通常のテキスト応答
|
# tool_outputをAIに返す
|
||||||
|
followup = {
|
||||||
|
"model": cfg["model"],
|
||||||
|
"messages": [
|
||||||
|
{"role": "system", "content": "あなたはAIで、必要に応じてツールmemoryを使って記憶を検索します。"},
|
||||||
|
{"role": "user", "content": message},
|
||||||
|
{"role": "assistant", "tool_calls": result["choices"][0]["message"]["tool_calls"]},
|
||||||
|
{"role": "tool", "tool_call_id": tool_call["id"], "name": "memory", "content": tool_output}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
print(tool_output)
|
||||||
|
print(cfg["model"])
|
||||||
|
|
||||||
|
res2 = requests.post(cfg["url"], headers=headers, json=followup)
|
||||||
|
res2.raise_for_status()
|
||||||
|
final_response = res2.json()
|
||||||
|
print(final_response)
|
||||||
|
return final_response["choices"][0]["message"]["content"]
|
||||||
|
|
||||||
|
# ツール未使用 or 通常応答
|
||||||
return result["choices"][0]["message"]["content"]
|
return result["choices"][0]["message"]["content"]
|
||||||
|
|
||||||
def call_ollama(cfg, message: str):
|
def call_ollama(cfg, message: str):
|
||||||
@ -127,7 +146,6 @@ def call_ollama(cfg, message: str):
|
|||||||
response = requests.post(cfg["url"], headers=headers, json=payload)
|
response = requests.post(cfg["url"], headers=headers, json=payload)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json().get("response", "❌ 応答が取得できませんでした")
|
return response.json().get("response", "❌ 応答が取得できませんでした")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print("Usage: ask.py 'your message'")
|
print("Usage: ask.py 'your message'")
|
||||||
|
@ -22,16 +22,29 @@ def save_message(sender, message):
|
|||||||
with open(path, "w") as f:
|
with open(path, "w") as f:
|
||||||
json.dump(logs, f, indent=2, ensure_ascii=False)
|
json.dump(logs, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
#def search_memory(query: str):
|
||||||
|
# from glob import glob
|
||||||
|
# all_logs = []
|
||||||
|
# for file_path in sorted(MEMORY_DIR.glob("*.json")):
|
||||||
|
# with open(file_path, "r") as f:
|
||||||
|
# logs = json.load(f)
|
||||||
|
# #matched = [entry for entry in logs if query in entry["message"]]
|
||||||
|
# matched = [entry for entry in logs if query.lower() in entry["message"].lower()]
|
||||||
|
# all_logs.extend(matched)
|
||||||
|
# return all_logs[-5:] # 最新5件だけ返す
|
||||||
|
|
||||||
def search_memory(query: str):
|
def search_memory(query: str):
|
||||||
from glob import glob
|
from glob import glob
|
||||||
all_logs = []
|
all_logs = []
|
||||||
|
pattern = re.compile(re.escape(query), re.IGNORECASE)
|
||||||
|
|
||||||
for file_path in sorted(MEMORY_DIR.glob("*.json")):
|
for file_path in sorted(MEMORY_DIR.glob("*.json")):
|
||||||
with open(file_path, "r") as f:
|
with open(file_path, "r") as f:
|
||||||
logs = json.load(f)
|
logs = json.load(f)
|
||||||
matched = [entry for entry in logs if query in entry["message"]]
|
matched = [entry for entry in logs if pattern.search(entry["message"])]
|
||||||
all_logs.extend(matched)
|
all_logs.extend(matched)
|
||||||
return all_logs[-5:] # 最新5件だけ返す
|
|
||||||
|
|
||||||
|
return all_logs[-5:]
|
||||||
|
|
||||||
# scripts/memory_store.py
|
# scripts/memory_store.py
|
||||||
import json
|
import json
|
||||||
@ -60,15 +73,31 @@ def save_message(sender, message):
|
|||||||
with open(path, "w") as f:
|
with open(path, "w") as f:
|
||||||
json.dump(logs, f, indent=2, ensure_ascii=False)
|
json.dump(logs, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
# キーワードで過去のメモリを検索する(最新5件を返す)
|
|
||||||
def search_memory(query: str):
|
def search_memory(query: str):
|
||||||
|
from glob import glob
|
||||||
all_logs = []
|
all_logs = []
|
||||||
for file_path in sorted(MEMORY_DIR.glob("*.json")):
|
for file_path in sorted(MEMORY_DIR.glob("*.json")):
|
||||||
try:
|
with open(file_path, "r") as f:
|
||||||
with open(file_path, "r") as f:
|
logs = json.load(f)
|
||||||
logs = json.load(f)
|
matched = [
|
||||||
matched = [entry for entry in logs if query.lower() in entry["message"].lower()]
|
entry for entry in logs
|
||||||
all_logs.extend(matched)
|
if entry["sender"] == "user" and query in entry["message"]
|
||||||
except Exception as e:
|
]
|
||||||
print(f"⚠️ 読み込み失敗: {file_path} ({e})")
|
all_logs.extend(matched)
|
||||||
return all_logs[-5:] # 最新5件を返す
|
return all_logs[-5:] # 最新5件だけ返す
|
||||||
|
def search_memory(query: str):
|
||||||
|
from glob import glob
|
||||||
|
all_logs = []
|
||||||
|
seen_messages = set() # すでに見たメッセージを保持
|
||||||
|
|
||||||
|
for file_path in sorted(MEMORY_DIR.glob("*.json")):
|
||||||
|
with open(file_path, "r") as f:
|
||||||
|
logs = json.load(f)
|
||||||
|
for entry in logs:
|
||||||
|
if entry["sender"] == "user" and query in entry["message"]:
|
||||||
|
# すでに同じメッセージが結果に含まれていなければ追加
|
||||||
|
if entry["message"] not in seen_messages:
|
||||||
|
all_logs.append(entry)
|
||||||
|
seen_messages.add(entry["message"])
|
||||||
|
|
||||||
|
return all_logs[-5:] # 最新5件だけ返す
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
# server.py
|
# server.py
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI, Body
|
||||||
from fastapi_mcp import FastApiMCP
|
from fastapi_mcp import FastApiMCP
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
#from memory_store import save_message, load_messages, search_memory
|
from memory_store import save_message, load_logs, search_memory as do_search_memory
|
||||||
from memory_store import save_message, load_logs, search_memory
|
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
mcp = FastApiMCP(app, name="aigpt-agent", description="MCP Server for AI memory")
|
mcp = FastApiMCP(app, name="aigpt-agent", description="MCP Server for AI memory")
|
||||||
@ -43,11 +42,37 @@ async def ask_message(input: MemoryQuery):
|
|||||||
"response": f"🔎 記憶から {len(results)} 件ヒット:\n" + "\n".join([f"{r['sender']}: {r['message']}" for r in results])
|
"response": f"🔎 記憶から {len(results)} 件ヒット:\n" + "\n".join([f"{r['sender']}: {r['message']}" for r in results])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## こちらはうまくいく
|
||||||
|
## curl -X POST http://127.0.0.1:5000/memory/search -H "Content-Type: application/json" -d '{"query": "昨日"}'
|
||||||
|
## {"result":"記憶の中から「昨日」に関するデータを返しました"}
|
||||||
|
#@app.post("/memory/search", operation_id="memory")
|
||||||
|
#async def search_memory(input: dict):
|
||||||
|
# query = input.get("query", "")
|
||||||
|
# results = do_search_memory(query)
|
||||||
|
# if not results:
|
||||||
|
# return {"result": "該当する記憶は見つかりませんでした"}
|
||||||
|
# return {
|
||||||
|
# "result": "記憶検索結果:\n" + "\n".join([f"{r['sender']}: {r['message']}" for r in results])
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
## こちらはうまくいかない
|
||||||
|
## curl -X POST http://127.0.0.1:5000/memory/search -H "Content-Type: application/json" -d '{"query": "昨日"}'
|
||||||
|
## Internal Server Error
|
||||||
|
#@app.post("/memory/search", operation_id="memory")
|
||||||
|
#async def memory_search(query: MemoryQuery):
|
||||||
|
# hits = search_memory(query.query)
|
||||||
|
# if not hits:
|
||||||
|
# return {"result": "🔍 記憶の中に該当する内容は見つかりませんでした。"}
|
||||||
|
# summary = "\n".join([f"{e['sender']}: {e['message']}" for e in hits])
|
||||||
|
# return {"result": f"🔎 見つかった記憶:\n{summary}"}
|
||||||
|
|
||||||
@app.post("/memory/search", operation_id="memory")
|
@app.post("/memory/search", operation_id="memory")
|
||||||
async def search_memory(input: dict):
|
async def memory_search(query: MemoryQuery):
|
||||||
query = input.get("query", "")
|
hits = do_search_memory(query.query) # ←ここを修正
|
||||||
# 適当なキーワード検索ロジックを追加(例: logs.jsonを検索)
|
if not hits:
|
||||||
return {"result": f"記憶の中から「{query}」に関するデータを返しました"}
|
return {"result": "🔍 記憶の中に該当する内容は見つかりませんでした。"}
|
||||||
|
summary = "\n".join([f"{e['sender']}: {e['message']}" for e in hits])
|
||||||
|
return {"result": f"🔎 見つかった記憶:\n{summary}"}
|
||||||
|
|
||||||
# --- MCP 初期化 ---
|
# --- MCP 初期化 ---
|
||||||
mcp.mount()
|
mcp.mount()
|
||||||
|
20
mcp/scripts/t.py
Normal file
20
mcp/scripts/t.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi_mcp import FastApiMCP
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
@app.get("/items/{item_id}", operation_id="get_item")
|
||||||
|
async def read_item(item_id: int):
|
||||||
|
return {"item_id": item_id, "name": f"Item {item_id}"}
|
||||||
|
|
||||||
|
# MCPサーバを作成し、FastAPIアプリにマウント
|
||||||
|
mcp = FastApiMCP(
|
||||||
|
app,
|
||||||
|
name="My API MCP",
|
||||||
|
description="My API description"
|
||||||
|
)
|
||||||
|
mcp.mount()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
Loading…
x
Reference in New Issue
Block a user