Commit fbf70318 authored by yuguo's avatar yuguo

fix

parent da795257
...@@ -59,14 +59,23 @@ func defaultAgentDefinitions() []model.AgentDefinition { ...@@ -59,14 +59,23 @@ func defaultAgentDefinitions() []model.AgentDefinition {
"trigger_workflow", "request_human_review", "trigger_workflow", "request_human_review",
"list_knowledge_collections", "send_notification", "list_knowledge_collections", "send_notification",
"query_drug", "search_medical_knowledge", "navigate_page", "query_drug", "search_medical_knowledge", "navigate_page",
// v17: 业务数据查询 // v17: 问诊 & 处方数据查询
"query_consultation_list", "query_consultation_detail", "query_consultation_list", "query_consultation_detail",
"query_prescription_list", "query_prescription_detail", "query_prescription_list", "query_prescription_detail",
"generate_tool", "query_waiting_queue",
// v17: 医生/科室/患者
"query_doctor_list", "query_doctor_detail", "query_department_list",
"query_patient_profile", "query_health_metrics",
// v17: 慢病 & 排班
"query_chronic_records", "query_renewal_requests",
"query_doctor_schedule",
// v17: 收入统计(管理员查看全局)
"query_income_stats", "query_income_records",
// v17: 管理统计 + 用户管理 + 系统日志 + 订单 // v17: 管理统计 + 用户管理 + 系统日志 + 订单
"query_dashboard_stats", "query_dashboard_trend", "query_dashboard_stats", "query_dashboard_trend",
"query_user_list", "query_system_logs", "query_user_list", "query_system_logs",
"query_order_list", "query_order_detail", "query_order_list", "query_order_detail",
"generate_tool",
}) })
return []model.AgentDefinition{ return []model.AgentDefinition{
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
// currentPromptVersion 当前代码中提示词模板的版本号 // currentPromptVersion 当前代码中提示词模板的版本号
// 每次修改提示词内容时递增此值,ensurePromptTemplates 会自动同步到数据库 // 每次修改提示词内容时递增此值,ensurePromptTemplates 会自动同步到数据库
const currentPromptVersion = 2 const currentPromptVersion = 3
// ensurePromptTemplates 确保所有内置提示词模板存在于数据库中(种子数据) // ensurePromptTemplates 确保所有内置提示词模板存在于数据库中(种子数据)
// 逻辑:不存在则创建;已存在但版本低于代码版本则更新内容 // 逻辑:不存在则创建;已存在但版本低于代码版本则更新内容
...@@ -37,7 +37,7 @@ func ensurePromptTemplates() { ...@@ -37,7 +37,7 @@ func ensurePromptTemplates() {
5. **药品查询**:查询药品信息、规格、用法和注意事项 5. **药品查询**:查询药品信息、规格、用法和注意事项
6. **问诊管理**:查询问诊列表和详情,帮助患者创建新的问诊(需指定医生和主诉) 6. **问诊管理**:查询问诊列表和详情,帮助患者创建新的问诊(需指定医生和主诉)
7. **处方查询**:查询处方列表和详情(药品明细、用法用量、费用) 7. **处方查询**:查询处方列表和详情(药品明细、用法用量、费用)
8. **健康档案**:查询个���健康档案、健康指标(血压/血糖/心率/体温)趋势、检验报告及AI解读 8. **健康档案**:查询个健康档案、健康指标(血压/血糖/心率/体温)趋势、检验报告及AI解读
9. **慢病管理**:查询慢病档案、创建慢病记录、申请续方、查看续方状态 9. **慢病管理**:查询慢病档案、创建慢病记录、申请续方、查看续方状态
10. **支付订单**:查询支付订单列表和详情,了解订单状态 10. **支付订单**:查询支付订单列表和详情,了解订单状态
...@@ -50,7 +50,7 @@ func ensurePromptTemplates() { ...@@ -50,7 +50,7 @@ func ensurePromptTemplates() {
- 当患者问"我的健康数据"时,使用 query_health_metrics 查询 - 当患者问"我的健康数据"时,使用 query_health_metrics 查询
- 当患者问"我的订单/支付"时,用 query_order_list 查询,用 query_order_detail 查详情 - 当患者问"我的订单/支付"时,用 query_order_list 查询,用 query_order_detail 查详情
- 当患者问慢病/续方时,用 query_chronic_records 和 query_renewal_requests 查询 - 当患者问慢病/续方时,用 query_chronic_records 和 query_renewal_requests 查询
- 当患者要记录血压/���糖等指标时,用 record_health_metric 记录 - 当患者要记录血压/糖等指标时,用 record_health_metric 记录
- 当患者查排班时,用 query_doctor_schedule 查询 - 当患者查排班时,用 query_doctor_schedule 查询
- 创建问诊前需确认患者提供了医生ID和主诉信息 - 创建问诊前需确认患者提供了医生ID和主诉信息
...@@ -61,7 +61,7 @@ func ensurePromptTemplates() { ...@@ -61,7 +61,7 @@ func ensurePromptTemplates() {
- 关注患者的用药依从性和健康状况变化 - 关注患者的用药依从性和健康状况变化
- 所有医疗建议仅供参考,请以专业医生判断为准 - 所有医疗建议仅供参考,请以专业医生判断为准
��导航能力: 导航能力:
- 你可以使用 navigate_page 工具为用户准备页面导航 - 你可以使用 navigate_page 工具为用户准备页面导航
- 【重要】调用工具后,页面不会自动打开,用户需要点击工具结果中的"打开页面"按钮才能跳转 - 【重要】调用工具后,页面不会自动打开,用户需要点击工具结果中的"打开页面"按钮才能跳转
- 因此你的回复应该说"我已为您准备好XXX页面,请点击下方按钮打开",而不是"已为您打开XXX页面" - 因此你的回复应该说"我已为您准备好XXX页面,请点击下方按钮打开",而不是"已为您打开XXX页面"
...@@ -132,27 +132,39 @@ func ensurePromptTemplates() { ...@@ -132,27 +132,39 @@ func ensurePromptTemplates() {
你的核心能力: 你的核心能力:
1. **运营数据**:查询仪表盘统计(用户数、医生数、问诊量、收入)和运营趋势 1. **运营数据**:查询仪表盘统计(用户数、医生数、问诊量、收入)和运营趋势
2. **Agent监控**:调用其他Agent获取信息,监控Agent运行状态 2. **医生管理**:查询医生列表、医生详情、排班信息、收入统计
3. **工作流管理**:触发和查询工作流执行状态 3. **科室管理**:查询科室列表
4. **知识库管理**:浏览知识库集合,了解知识库使用情况 4. **患者管理**:查询患者档案、健康指标
5. **人工审核**:发起和管理人工审核任务 5. **问诊管理**:查看问诊记录、等候队列
6. **通知管理**:发送系统通知 6. **处方管理**:查看处方记录
7. **药品/医学查询**:查询药品信息和医学知识辅助决策 7. **慢病管理**:查看慢病记录、续方申请
8. **业务数据查询**:查看问诊记录、处方记录、支付订单,支持全局查看 8. **订单管理**:查看支付订单
9. **用户管理**:查询系统用户列表,按角色/状态/关键词搜索 9. **用户管理**:查询系统用户列表,按角色/状态/关键词搜索
10. **系统日志**:查看系统操作日志,按操作类型和资源过滤 10. **系统日志**:查看系统操作日志
11. **Agent监控**:调用其他Agent获取信息,监控Agent运行状态
12. **工作流管理**:触发和查询工作流执行状态
13. **知识库管理**:浏览知识库集合
14. **通知管理**:发送系统通知
工具使用指南: 工具使用指南:
- 查运营数据用 query_dashboard_stats,查趋势用 query_dashboard_trend - 查运营数据用 query_dashboard_stats,查趋势用 query_dashboard_trend
- 查用户列表用 query_user_list,查系统日志用 query_system_logs - 查医生列表用 query_doctor_list,查医生详情用 query_doctor_detail
- 查科室列表用 query_department_list
- 查患者档案用 query_patient_profile,查健康指标用 query_health_metrics
- 查问诊数据用 query_consultation_list / query_consultation_detail - 查问诊数据用 query_consultation_list / query_consultation_detail
- 查等候队列用 query_waiting_queue
- 查处方数据用 query_prescription_list / query_prescription_detail - 查处方数据用 query_prescription_list / query_prescription_detail
- 查慢病记录用 query_chronic_records,查续方申请用 query_renewal_requests
- 查排班信息用 query_doctor_schedule
- 查收入统计用 query_income_stats,查收入明细用 query_income_records
- 查订单数据用 query_order_list / query_order_detail - 查订单数据用 query_order_list / query_order_detail
- 查用户列表用 query_user_list,查系统日志用 query_system_logs
- 需要新的数据查询能力时,使用 generate_tool 动态生成 SQL 工具 - 需要新的数据查询能力时,使用 generate_tool 动态生成 SQL 工具
使用原则: 使用原则:
- 以简洁专业的方式回答管理员的问题 - 以简洁专业的方式回答管理员的问题
- 主动使用工具获取真实数据 - 主动使用工具获取真实数据,不要说工具不可用
- 当用户询问某类数据时,直接调用对应工具查询
- 提供可操作的建议和方案 - 提供可操作的建议和方案
- 用中文回答 - 用中文回答
......
...@@ -281,7 +281,16 @@ func (s *AgentService) Chat(ctx context.Context, agentID, userID, userRole, sess ...@@ -281,7 +281,16 @@ func (s *AgentService) Chat(ctx context.Context, agentID, userID, userRole, sess
var history []ai.ChatMessage var history []ai.ChatMessage
if session.History != "" && session.History != "[]" { if session.History != "" && session.History != "[]" {
json.Unmarshal([]byte(session.History), &history) // 富格式 history 含 tool_calls/meta 等字段,只提取 role+content 给 AI 推理
var rawHistory []map[string]interface{}
json.Unmarshal([]byte(session.History), &rawHistory)
for _, h := range rawHistory {
role, _ := h["role"].(string)
content, _ := h["content"].(string)
if role != "" {
history = append(history, ai.ChatMessage{Role: role, Content: content})
}
}
} }
input := agent.AgentInput{ input := agent.AgentInput{
...@@ -296,12 +305,25 @@ func (s *AgentService) Chat(ctx context.Context, agentID, userID, userRole, sess ...@@ -296,12 +305,25 @@ func (s *AgentService) Chat(ctx context.Context, agentID, userID, userRole, sess
return nil, err return nil, err
} }
// 更新会话 // 更新会话(富消息格式,包含推理信息)
history = append(history, var richHistory []map[string]interface{}
ai.ChatMessage{Role: "user", Content: message}, if session.History != "" && session.History != "[]" {
ai.ChatMessage{Role: "assistant", Content: output.Response}, json.Unmarshal([]byte(session.History), &richHistory)
}
richHistory = append(richHistory,
map[string]interface{}{"role": "user", "content": message},
map[string]interface{}{
"role": "assistant",
"content": output.Response,
"tool_calls": output.ToolCalls,
"meta": map[string]interface{}{
"iterations": output.Iterations,
"tokens": output.TotalTokens,
"agent_id": agentID,
},
},
) )
historyJSON, _ := json.Marshal(history) historyJSON, _ := json.Marshal(richHistory)
contextJSON, _ := json.Marshal(contextData) contextJSON, _ := json.Marshal(contextData)
currentPage := "" currentPage := ""
...@@ -392,15 +414,25 @@ func (s *AgentService) ChatStream(ctx context.Context, agentID, userID, userRole ...@@ -392,15 +414,25 @@ func (s *AgentService) ChatStream(ctx context.Context, agentID, userID, userRole
sessionJSON, _ := json.Marshal(map[string]string{"session_id": sessionID}) sessionJSON, _ := json.Marshal(map[string]string{"session_id": sessionID})
emit("session", string(sessionJSON)) emit("session", string(sessionJSON))
// saveSession 统一的会话保存函数 // saveSession 统一的会话保存函数(保存富消息格式,包含推理信息)
saveSession := func(responseText string, tokens int) { saveSession := func(responseText string, tokens int, toolCalls interface{}, iterations int) {
var history []ai.ChatMessage // 使用富消息格式保存,前端恢复时可还原 toolCalls 和 meta
var history []map[string]interface{}
if session.History != "" && session.History != "[]" { if session.History != "" && session.History != "[]" {
json.Unmarshal([]byte(session.History), &history) json.Unmarshal([]byte(session.History), &history)
} }
history = append(history, history = append(history,
ai.ChatMessage{Role: "user", Content: message}, map[string]interface{}{"role": "user", "content": message},
ai.ChatMessage{Role: "assistant", Content: responseText}, map[string]interface{}{
"role": "assistant",
"content": responseText,
"tool_calls": toolCalls,
"meta": map[string]interface{}{
"iterations": iterations,
"tokens": tokens,
"agent_id": agentID,
},
},
) )
historyJSON, _ := json.Marshal(history) historyJSON, _ := json.Marshal(history)
contextJSON, _ := json.Marshal(contextData) contextJSON, _ := json.Marshal(contextData)
...@@ -473,7 +505,7 @@ func (s *AgentService) ChatStream(ctx context.Context, agentID, userID, userRole ...@@ -473,7 +505,7 @@ func (s *AgentService) ChatStream(ctx context.Context, agentID, userID, userRole
"mode": result.Mode, "mode": result.Mode,
}) })
emit("done", string(doneData)) emit("done", string(doneData))
saveSession(result.FinalResponse, 0) saveSession(result.FinalResponse, 0, nil, len(result.StepResults))
return return
} }
} }
...@@ -482,7 +514,16 @@ func (s *AgentService) ChatStream(ctx context.Context, agentID, userID, userRole ...@@ -482,7 +514,16 @@ func (s *AgentService) ChatStream(ctx context.Context, agentID, userID, userRole
// 普通 Agent 执行 // 普通 Agent 执行
var history []ai.ChatMessage var history []ai.ChatMessage
if session.History != "" && session.History != "[]" { if session.History != "" && session.History != "[]" {
json.Unmarshal([]byte(session.History), &history) // 富格式 history 含 tool_calls/meta 等字段,只提取 role+content 给 AI 推理
var rawHistory []map[string]interface{}
json.Unmarshal([]byte(session.History), &rawHistory)
for _, h := range rawHistory {
role, _ := h["role"].(string)
content, _ := h["content"].(string)
if role != "" {
history = append(history, ai.ChatMessage{Role: role, Content: content})
}
}
} }
input := agent.AgentInput{ input := agent.AgentInput{
...@@ -512,7 +553,7 @@ func (s *AgentService) ChatStream(ctx context.Context, agentID, userID, userRole ...@@ -512,7 +553,7 @@ func (s *AgentService) ChatStream(ctx context.Context, agentID, userID, userRole
} }
} }
saveSession(output.Response, output.TotalTokens) saveSession(output.Response, output.TotalTokens, output.ToolCalls, output.Iterations)
// 记录执行日志 // 记录执行日志
inputJSON, _ := json.Marshal(input) inputJSON, _ := json.Marshal(input)
......
...@@ -38,23 +38,23 @@ func (t *DashboardStatsTool) Execute(ctx context.Context, params map[string]inte ...@@ -38,23 +38,23 @@ func (t *DashboardStatsTool) Execute(ctx context.Context, params map[string]inte
// 总用户数 // 总用户数
t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM users WHERE deleted_at IS NULL").Scan(&count) t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM users WHERE deleted_at IS NULL").Scan(&count)
stats["total_users"] = count stats["总用户数"] = count
// 总医生数 // 总医生数
t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM users WHERE role = 'doctor' AND deleted_at IS NULL").Scan(&count) t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM users WHERE role = 'doctor' AND deleted_at IS NULL").Scan(&count)
stats["total_doctors"] = count stats["总医生数"] = count
// 总问诊数 // 总问诊数
t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM consultations WHERE deleted_at IS NULL").Scan(&count) t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM consultations WHERE deleted_at IS NULL").Scan(&count)
stats["total_consultations"] = count stats["总问诊数"] = count
// 今日问诊数 // 今日问诊数
t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM consultations WHERE DATE(created_at) = ? AND deleted_at IS NULL", today).Scan(&count) t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM consultations WHERE DATE(created_at) = ? AND deleted_at IS NULL", today).Scan(&count)
stats["today_consultations"] = count stats["今日问诊"] = count
// 待审核医生数 // 待审核医生数
t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM doctor_reviews WHERE status = 'pending'").Scan(&count) t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM doctor_reviews WHERE status = 'pending'").Scan(&count)
stats["pending_doctor_reviews"] = count stats["待审核医生"] = count
// 今日收入(已支付订单) // 今日收入(已支付订单)
var todayRevenue int64 var todayRevenue int64
...@@ -62,7 +62,7 @@ func (t *DashboardStatsTool) Execute(ctx context.Context, params map[string]inte ...@@ -62,7 +62,7 @@ func (t *DashboardStatsTool) Execute(ctx context.Context, params map[string]inte
"SELECT COALESCE(SUM(amount), 0) FROM payment_orders WHERE DATE(paid_at) = ? AND status = 'paid' AND deleted_at IS NULL", "SELECT COALESCE(SUM(amount), 0) FROM payment_orders WHERE DATE(paid_at) = ? AND status = 'paid' AND deleted_at IS NULL",
today, today,
).Scan(&todayRevenue) ).Scan(&todayRevenue)
stats["revenue_today"] = todayRevenue stats["今日收入"] = todayRevenue
// 本月收入 // 本月收入
var monthRevenue int64 var monthRevenue int64
...@@ -70,11 +70,11 @@ func (t *DashboardStatsTool) Execute(ctx context.Context, params map[string]inte ...@@ -70,11 +70,11 @@ func (t *DashboardStatsTool) Execute(ctx context.Context, params map[string]inte
"SELECT COALESCE(SUM(amount), 0) FROM payment_orders WHERE paid_at >= ? AND status = 'paid' AND deleted_at IS NULL", "SELECT COALESCE(SUM(amount), 0) FROM payment_orders WHERE paid_at >= ? AND status = 'paid' AND deleted_at IS NULL",
monthStart, monthStart,
).Scan(&monthRevenue) ).Scan(&monthRevenue)
stats["revenue_month"] = monthRevenue stats["本月收入"] = monthRevenue
// 总处方数 // 总处方数
t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM prescriptions WHERE deleted_at IS NULL").Scan(&count) t.DB.WithContext(ctx).Raw("SELECT COUNT(*) FROM prescriptions WHERE deleted_at IS NULL").Scan(&count)
stats["total_prescriptions"] = count stats["总处方数"] = count
return stats, nil return stats, nil
} }
...@@ -62,9 +62,9 @@ func (t *DashboardTrendTool) Execute(ctx context.Context, params map[string]inte ...@@ -62,9 +62,9 @@ func (t *DashboardTrendTool) Execute(ctx context.Context, params map[string]inte
var consultCount, completedCount int var consultCount, completedCount int
if err := rows.Scan(&date, &consultCount, &completedCount); err == nil { if err := rows.Scan(&date, &consultCount, &completedCount); err == nil {
results = append(results, map[string]interface{}{ results = append(results, map[string]interface{}{
"date": date, "日期": date,
"consult_count": consultCount, "问诊量": consultCount,
"completed_count": completedCount, "完成量": completedCount,
}) })
} }
} }
...@@ -73,7 +73,7 @@ func (t *DashboardTrendTool) Execute(ctx context.Context, params map[string]inte ...@@ -73,7 +73,7 @@ func (t *DashboardTrendTool) Execute(ctx context.Context, params map[string]inte
} }
return map[string]interface{}{ return map[string]interface{}{
"trend": results, "趋势数据": results,
"days": days, "天数": days,
}, nil }, nil
} }
...@@ -64,8 +64,8 @@ func (t *IncomeStatsTool) Execute(ctx context.Context, params map[string]interfa ...@@ -64,8 +64,8 @@ func (t *IncomeStatsTool) Execute(ctx context.Context, params map[string]interfa
).Scan(&monthConsults) ).Scan(&monthConsults)
return map[string]interface{}{ return map[string]interface{}{
"total_balance": totalBalance, "可提现余额": totalBalance,
"month_income": monthIncome, "本月收入": monthIncome,
"month_consults": monthConsults, "本月问诊量": monthConsults,
}, nil }, nil
} }
...@@ -102,13 +102,20 @@ const ChatPanel: React.FC<ChatPanelProps> = ({ role, patientContext }) => { ...@@ -102,13 +102,20 @@ const ChatPanel: React.FC<ChatPanelProps> = ({ role, patientContext }) => {
const latest = sessions[0]; const latest = sessions[0];
setSessionId(latest.session_id); setSessionId(latest.session_id);
// 尝试恢复历史消息 // 尝试恢复历史消息(富格式:包含 tool_calls 和 meta)
try { try {
const history = JSON.parse(latest.history || '[]') as { role: string; content: string }[]; const history = JSON.parse(latest.history || '[]') as Array<{
role: string;
content: string;
tool_calls?: ToolCall[];
meta?: { iterations?: number; tokens?: number; agent_id?: string };
}>;
if (history.length > 0) { if (history.length > 0) {
const restored: ChatMessage[] = history.map(h => ({ const restored: ChatMessage[] = history.map(h => ({
role: h.role as 'user' | 'assistant', role: h.role as 'user' | 'assistant',
content: h.content, content: h.content,
toolCalls: h.tool_calls || undefined,
meta: h.meta || undefined,
timestamp: new Date(), timestamp: new Date(),
})); }));
setMessages(restored); setMessages(restored);
...@@ -283,8 +290,8 @@ const ChatPanel: React.FC<ChatPanelProps> = ({ role, patientContext }) => { ...@@ -283,8 +290,8 @@ const ChatPanel: React.FC<ChatPanelProps> = ({ role, patientContext }) => {
return ( return (
<div style={{ marginTop: 6 }}> <div style={{ marginTop: 6 }}>
{toolCalls.map((tc, idx) => ( {toolCalls.map((tc, idx) => (
<div key={idx}>
<ToolCallCard <ToolCallCard
key={idx}
toolName={tc.tool_name} toolName={tc.tool_name}
arguments={tc.arguments} arguments={tc.arguments}
callId={tc.call_id} callId={tc.call_id}
...@@ -295,16 +302,6 @@ const ChatPanel: React.FC<ChatPanelProps> = ({ role, patientContext }) => { ...@@ -295,16 +302,6 @@ const ChatPanel: React.FC<ChatPanelProps> = ({ role, patientContext }) => {
: 'running' : 'running'
} }
/> />
{tc.result && (tc.success || tc.result.error) && (
<div style={{ marginTop: 4, marginLeft: 4 }}>
<ToolResultCard
toolName={tc.tool_name}
success={tc.success}
result={tc.result}
/>
</div>
)}
</div>
))} ))}
</div> </div>
); );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment