74 lines
3.2 KiB
Go
74 lines
3.2 KiB
Go
package coordinator
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"strings"
|
|
|
|
"chat-agent-system/internal/intent"
|
|
)
|
|
|
|
// FactBlock 是本轮答复允许引用的确定性事实。模型只组织语言,不补充事实。
|
|
type FactBlock struct {
|
|
Title string
|
|
Body string
|
|
}
|
|
|
|
const agentNarrativeInstruction = `只把【本轮事实】中的「系统确定性底稿」改写成项目助手的自然中文,并写入 reply.md。
|
|
不得新增底稿没有的标准编号、条款、数值、文档状态或执行结果;不得删除底稿中的文档名、路径、数字与〔引用键〕。
|
|
若底稿写明尚未执行、需要确认或请到项目设置界面操作,答复必须保留该边界,不得宣称已经完成。`
|
|
|
|
const intentReplyInstructions = `你是「水木东方」医疗器械「项目助手」。只以项目助手自称。
|
|
本轮任务是把系统已经确定的事实组织成自然答复,不是重新检索或执行操作。
|
|
1. 【本轮事实】是唯一事实来源。底稿未写出的标准编号、条款、项目数据、文档状态与执行结果一律不得编造。
|
|
2. 保留底稿中的文档名、路径、数字、角色与〔引用键〕。
|
|
3. 底稿若说明需要确认、权限不足、或请到项目设置界面操作,必须原意保留,不得改成已经执行。
|
|
4. 使用中文,只把最终答复写入 reply.md。`
|
|
|
|
// narrateReply 优先用智能体改写确定性底稿;失败或关闭时原样返回模板。
|
|
func (e *CoordinatorEngine) narrateReply(
|
|
ctx context.Context,
|
|
userCtx *UserProjectContext,
|
|
handler string,
|
|
it intent.IntentType,
|
|
rawInput, template, instruction string,
|
|
) (string, string) {
|
|
template = strings.TrimSpace(template)
|
|
if template == "" || !agentReplyLLMEnabled() || e == nil || e.dialogueBackend == nil {
|
|
return template, ReplySourceTemplate
|
|
}
|
|
if strings.TrimSpace(instruction) == "" {
|
|
instruction = agentNarrativeInstruction
|
|
}
|
|
e.ensureProjectDialogueSnippet(ctx, userCtx)
|
|
prompt := NewMemoryComposer().ComposeIntentReplyPrompt(rawInput, userCtx, string(it), []FactBlock{{
|
|
Title: "系统确定性底稿",
|
|
Body: template,
|
|
}}, instruction)
|
|
content, reason := e.runDialogueBackend(ctx, userCtx, prompt, intentReplyInstructions, "intent_reply_generating", "正在组织项目助手回复...")
|
|
if reason != "" || strings.TrimSpace(content) == "" {
|
|
if reason != "" && reason != "backend_nil" && reason != "no_data_dir" {
|
|
slog.InfoContext(ctx, "agent_reply_fallback", "handler", handler, "intent", string(it), "reason", reason)
|
|
}
|
|
return template, ReplySourceTemplate
|
|
}
|
|
return strings.TrimSpace(content), ReplySourcePiAgent
|
|
}
|
|
|
|
// applyNarrative 用智能体叙述替换已生成结果的 NaturalReply,并写入 ReplySource。
|
|
// 调用方只应对知识叙述、帮助导航和已完成/已受理通报使用;确认提问与权限拒绝不要调用。
|
|
func (e *CoordinatorEngine) applyNarrative(
|
|
ctx context.Context,
|
|
userCtx *UserProjectContext,
|
|
handler, rawInput, instruction string,
|
|
res *CoordinationResult,
|
|
) *CoordinationResult {
|
|
if res == nil {
|
|
return nil
|
|
}
|
|
reply, source := e.narrateReply(ctx, userCtx, handler, res.Intent, rawInput, res.NaturalReply, instruction)
|
|
res.NaturalReply = reply
|
|
res.ReplySource = source
|
|
return res
|
|
}
|