projects/repobot/v3/agent.py
49 lignes · 2.7 KoLe code et les sorties des programmes sont reproduits tels qu’ils ont tourné : commentaires et sorties sont donc en chinois.
"""RepoBot v3 的智能体循环,和 05 模块第 2 课的写法相同,加上了费用统计和执行轨迹。"""
import json
import llm
from tools import TOOLS
SYSTEM = """你是 RepoBot,Python HTTP 客户端库 httpx 的答疑助手。你可以查 httpx 的官方文档和源码。
做法:
- 先用 search_docs 查文档。文档里有答案,就根据文档回答。
- 文档里没有答案(比如默认值、内部逻辑、某个异常什么时候抛出),再用 grep_source 和 read_source 查源码。
- 回答里注明依据:文档写成 [文档 文件名],源码写成 [源码 文件路径:行号]。
- 只根据查到的内容回答。查了还是找不到,就如实说没有找到,不要猜。
- 和 httpx 无关的问题,直接礼貌地说明你只负责 httpx,不要调用任何工具。
- 用中文回答,简洁,代码保持原样。"""
MAX_STEPS = 10
MAX_OBSERVATION = 4000
def run(question, history=(), show=print):
"""回答一个问题。返回 (回答, 统计)。history 是之前几轮的 user/assistant 消息。"""
messages = [{"role": "system", "content": SYSTEM}, *history, {"role": "user", "content": question}]
schemas = [t["schema"] for t in TOOLS.values()]
stats = {"steps": 0, "tool_calls": 0, "cost": 0.0, "prompt_tokens": 0}
for step in range(1, MAX_STEPS + 1):
response = llm.with_retry(lambda: llm.client.chat.completions.create(
model=llm.MODEL, messages=messages, tools=schemas, extra_body={"thinking": {"type": "disabled"}}))
message = response.choices[0].message
stats["steps"] = step
stats["cost"] += llm.cost_usd(response.usage)
stats["prompt_tokens"] += response.usage.prompt_tokens
if not message.tool_calls:
return message.content, stats
messages.append(message.model_dump(exclude_none=True))
for call in message.tool_calls:
stats["tool_calls"] += 1
try:
result = TOOLS[call.function.name]["fn"](**json.loads(call.function.arguments or "{}"))
except KeyError:
result = f"错误:没有叫 {call.function.name} 的工具"
except Exception as e:
result = f"错误:{type(e).__name__}: {e}"
if len(result) > MAX_OBSERVATION:
result = result[:MAX_OBSERVATION] + f"\n……(已截断,共 {len(result)} 字符)"
show(f" [{step}] {call.function.name}({call.function.arguments}) → {result.splitlines()[0][:70] if result else ''}")
messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
return "这个问题查了很多步还没有得出结论,我先停下来。可以换个问法,或者问得更具体一些。", stats