module/file.py:function_nameknowhub/docs/decisions.md 另行记录当前的知识反馈存在以下问题(来自 feedback-optimization-proposal.md):
每个 trace 维护一个 knowledge_log.json,记录该 trace 中所有被注入的知识及其评估状态。
位置:.trace/{trace_id}/knowledge_log.json
数据结构:
{
"trace_id": "trace-xxx",
"entries": [
{
"knowledge_id": "knowledge-20260305-a1b2",
"goal_id": "1",
"injected_at_sequence": 42,
"injected_at": "2026-03-20T10:00:00.000000",
"task": "知识的原始task描述",
"content": "知识内容摘要(截断至500字符)",
"eval_result": {
"eval_status": "helpful",
"reason": "评估理由"
},
"evaluated_at": "2026-03-20T10:05:00.000000",
"evaluated_at_trigger": "goal_completion"
}
]
}
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
knowledge_id |
string | KnowHub 中的知识 ID |
goal_id |
string | 注入时的 Goal ID(如 "1", "2.1") |
injected_at_sequence |
int | 注入时的消息序列号 |
injected_at |
datetime | 注入时间(ISO 格式,含毫秒) |
task |
string | 知识的原始 task 描述 |
content |
string | 知识内容(写入时截断至 500 字符) |
eval_result |
object/null | 评估结果对象;未评估时为 null |
evaluated_at |
datetime/null | 评估时间;未评估时为 null |
evaluated_at_trigger |
string/null | 触发评估的事件(见下表);未评估时为 null |
evaluated_at_trigger 可能的值:
| 值 | 含义 |
|---|---|
"goal_completion" |
由 Goal 完成(completed 或 abandoned)触发 |
"compression" |
由上下文压缩触发(压缩前必须先评估) |
"task_completion" |
由任务自然结束触发(主路径无工具调用退出时兜底) |
注意:同一个
knowledge_id可能在不同 Goal 中被多次注入,每次产生独立 entry。评估时优先更新最近注入(injected_at_sequence最大)的未评估条目。
时机:Goal status 变为 completed 或 abandoned
触发逻辑(agent/trace/store.py:update_goal):
Goal 完成
↓
查询 knowledge_log 中 eval_result == null 的条目
↓
如果有待评估条目
→ 在 trace.context 中设置标志:
pending_knowledge_eval = true
knowledge_eval_trigger = "goal_completion"
↓
Runner 主循环下一次迭代开头检测到标志(agent/core/runner.py:_agent_loop)
→ 清除标志
→ 将 "knowledge_eval" 加入 force_side_branch 队列
时机:上下文 token 数超过阈值,即将执行压缩
触发逻辑(agent/core/runner.py:_manage_context_usage):
压缩条件触发
↓
查询 knowledge_log 中 eval_result == null 的条目
↓
如果有待评估条目
→ 在 trace.context 中设置:
knowledge_eval_trigger = "compression"
→ 将侧分支队列设为:
["reflection", "knowledge_eval", "compression"](启用知识提取时)
["knowledge_eval", "compression"](未启用知识提取时)
→ 返回"需要进入侧分支"信号,暂缓压缩
↓
依次执行侧分支队列后再压缩
原因:压缩会删除消息历史,必须在压缩前完成评估,否则执行上下文永久丢失。
时机:主路径出现无工具调用的回复,Agent 即将结束任务
触发逻辑(agent/core/runner.py:_agent_loop,无工具调用分支):
主路径无工具调用(任务即将结束)
↓
查询 knowledge_log 中 eval_result == null 的条目
↓
如果有待评估条目
→ 在 trace.context 中设置:
knowledge_eval_trigger = "task_completion"
→ 将 ["knowledge_eval"] 加入 force_side_branch 队列
→ continue(不 break,下一轮执行评估侧分支)
↓
评估完成后再退出
| 状态 | 含义 |
|---|---|
irrelevant |
知识的 task 与当前任务无关 |
unused |
知识与任务相关,但执行过程中没有被使用 |
helpful |
知识对当前任务有实质帮助 |
harmful |
知识对当前任务产生了负面作用 |
neutral |
知识与任务相关但无明显影响 |
复用现有 SideBranchContext 机制,新增 "knowledge_eval" 类型(agent/trace/models.py:Message.branch_type):
SideBranchContext(
type="knowledge_eval",
branch_id=f"knowledge_eval_{uuid.uuid4().hex[:8]}", # 如 "knowledge_eval_1c5fffaf"
max_turns=config.side_branch_max_turns # 默认 5
)
trigger_event 记录在 trace.context["active_side_branch"]["trigger_event"] 中,侧分支退出后写入 evaluated_at_trigger。
完整实现见 agent/core/runner.py:_build_knowledge_eval_prompt,结构如下:
你是知识评估助手。请评估以下知识在本次任务执行中的实际效果。
## 当前任务(Mission) ← trace.task
## 当前 Goal ← goal_tree.current 的 description
## 待评估知识列表 ← 所有 eval_result == null 的条目
- knowledge_id / task / content / injected_at_sequence / goal_id
## 评估维度 ← helpfulness + relevance
## 评估分类 ← 5 个 eval_status 选项
## 输出格式 ← JSON
Prompt 中不包含消息历史。LLM 依据对话上下文中已有的执行过程作出判断。
LLM 直接输出 JSON,无需调用工具:
{
"evaluations": [
{
"knowledge_id": "knowledge-20260305-a1b2",
"eval_status": "helpful",
"reason": "1-2句评估理由"
}
]
}
agent/core/runner.py:_agent_loop)每次 LLM 回复后立即尝试解析,三种策略依次降级:整体解析 → `json 代码块 → 正则裸对象。
LLM 输出评估 JSON
↓
解析成功 → 立即调用 store.update_knowledge_evaluation() 写入每条评估结果
↓
侧分支达到退出条件(无工具调用 或 超过 max_turns)→ 恢复主路径
解析失败时记录日志,不中断主流程。
知识注入(agent/trace/goal_tool.py:inject_knowledge_for_goal)
↓
写入 knowledge_log.json(eval_result=null)
↓
┌─────────────────────────────────────────────┐
│ 触发点 A:Goal 完成(goal_completion) │
│ 触发点 B:压缩执行前(compression) │
│ 触发点 C:任务自然结束(task_completion) │
└─────────────────────────────────────────────┘
↓
Runner 进入 knowledge_eval 侧分支
↓
LLM 直接输出 JSON 评估结果(无工具调用)
↓
Runner 每轮即时解析并写入 knowledge_log.json
↓
侧分支退出 → 恢复主路径
| 集成位置 | 文件 | 说明 |
|---|---|---|
| 知识注入时写 log | agent/trace/goal_tool.py:inject_knowledge_for_goal |
goal(focus=...) 触发知识搜索后写入 knowledge_log.json |
| Goal 完成时设置标志 | agent/trace/store.py:update_goal |
设置 trace.context["pending_knowledge_eval"] 标志 |
| 主循环检测 Goal 完成标志 | agent/core/runner.py:_agent_loop |
每轮迭代开头检测标志,触发 ["knowledge_eval"] 侧分支 |
| 压缩前触发评估 | agent/core/runner.py:_manage_context_usage |
压缩前检查 pending,先评估再压缩 |
| 任务结束兜底 | agent/core/runner.py:_agent_loop |
任务退出前检查 pending,强制触发评估 |
| 侧分支类型扩展 | agent/trace/models.py:Message.branch_type |
Literal 中包含 "knowledge_eval" |
| 即时写入评估结果 | agent/core/runner.py:_agent_loop |
存储 assistant 消息后即时解析 JSON 并写入 |
| Log 文件管理 | agent/trace/store.py |
append_knowledge_entry / update_knowledge_evaluation / get_pending_knowledge_entries |