tmp
This commit is contained in:
@@ -1,20 +1,24 @@
|
||||
import 'dotenv/config';
|
||||
import { createDeepAgent, FilesystemBackend } from "deepagents";
|
||||
import { AIMessageChunk, ToolMessage } from "langchain";
|
||||
import { createDeepAgent } from "deepagents";
|
||||
import { AIMessageChunk, ToolMessage, todoListMiddleware } from "langchain";
|
||||
import { HumanMessage } from "@langchain/core/messages";
|
||||
import { ChatDeepSeek } from "@langchain/deepseek";
|
||||
import config from '../../conf.json' with { type: 'json' };
|
||||
import logger from '../../utils/logger.js';
|
||||
import config from '../../../conf.json' with { type: 'json' };
|
||||
import logger from '../../../utils/logger.js';
|
||||
import { createRestrictedBackend } from "../../infra/restricted_fs_backend.js";
|
||||
|
||||
// 密钥由 conf.json 统一提供;百度地图 skill 通过 env_get 读环境变量,此处桥接
|
||||
process.env.TAVILY_API_KEY ??= config.agent.tavily?.apiKey;
|
||||
process.env.BAIDU_MAP_AUTH_TOKEN ??= config.agent.baiduMap?.authToken;
|
||||
import EscortAdminPrompts from "./prompts.js";
|
||||
import { createPatientRecordSubagent } from "../../subagent/patient_record.js";
|
||||
import { createResearchSubagent } from "../../subagent/research.js";
|
||||
import { createHospitalInfoSubagent } from "../../subagent/hospital_info.js";
|
||||
import {
|
||||
getEnvTool, webFetchTool, webSearchTool, getCalendarInfoTool,
|
||||
getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool, getLatLngTool,
|
||||
httpGetTool, httpPostTool, escortRecordQueryTool, escortRecordSetTool
|
||||
} from "./tools/index.js";
|
||||
} from "../../infra/tools/index.js";
|
||||
|
||||
export default class EscortAdminAgent {
|
||||
constructor() {
|
||||
@@ -126,7 +130,8 @@ export default class EscortAdminAgent {
|
||||
|
||||
_genAgent(userInfo) {
|
||||
const rootDir = process.cwd();
|
||||
const backend = new FilesystemBackend({ rootDir });
|
||||
// 受限后端:锁定沙箱根并禁止读取 conf.json/.env/logs 及用户数据目录
|
||||
const backend = createRestrictedBackend({ rootDir, dataDir: config.agent.dataDir });
|
||||
|
||||
this.flashModel = new ChatDeepSeek({
|
||||
model: config.agent.deepseek.flashModel,
|
||||
@@ -139,31 +144,16 @@ export default class EscortAdminAgent {
|
||||
temperature: 0.3
|
||||
});
|
||||
|
||||
const escortRecordOperSubagent = {
|
||||
name: "escort-record-oper-subagent",
|
||||
description: "查询和设置陪诊预约记录",
|
||||
systemPrompt: "根据用户指令,调用工具完成查询和设置陪诊记录。",
|
||||
model: this.flashModel,
|
||||
tools: [escortRecordQueryTool, escortRecordSetTool],
|
||||
};
|
||||
|
||||
const escortResearchSubagent = {
|
||||
name: "escort-research-subagent",
|
||||
description: "陪诊(陪同就医)行业问题研究和解答",
|
||||
systemPrompt: "你是陪诊(陪同就医)行业政策、发展趋势、行业知识研究和解答专家。",
|
||||
model: this.proModel,
|
||||
tools: [webFetchTool, webSearchTool],
|
||||
};
|
||||
|
||||
return createDeepAgent({
|
||||
name: "deep-agent",
|
||||
model: this.flashModel,
|
||||
systemPrompt: EscortAdminPrompts.buildSystemPrompt(userInfo),
|
||||
backend,
|
||||
middleware: [todoListMiddleware()], // deepagents 1.12 起 todo 计划工具改为显式开启,多步记录操作用
|
||||
tools: [getEnvTool, webFetchTool, webSearchTool, getLatLngTool, httpGetTool, httpPostTool,
|
||||
getCalendarInfoTool, getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool,
|
||||
escortRecordQueryTool, escortRecordSetTool],
|
||||
subagents: [escortRecordOperSubagent, escortResearchSubagent]
|
||||
subagents: [createPatientRecordSubagent(this.flashModel), createResearchSubagent(this.proModel), createHospitalInfoSubagent(this.flashModel)]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import services from "../../resource/services.js";
|
||||
import agreement from "../../resource/agreement.js";
|
||||
import services from "../../../resource/services.js";
|
||||
import agreement from "../../../resource/agreement.js";
|
||||
|
||||
class EscortAdminPrompts {
|
||||
static buildSystemPrompt(userInfo) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
`/memories/` 目录用于持久化存储用户信息,在每次会话开始时自动加载。
|
||||
|
||||
## 长期记忆
|
||||
当用户分享以下信息时,使用 `write_file` 将其保存到 `/memories/user_memory.txt`:
|
||||
当用户分享以下信息时,使用 `write_file` 将其保存到 `/memories/memory.txt`:
|
||||
- 个人基本信息、生活习惯、个人喜好
|
||||
- 健康或医疗相关的任何信息(身体健康、看病、住院、手术、病情、用药、过敏、体质、病历、检查报告、长期健康目标等)
|
||||
- 医疗信息要记录对应的日期时间,如果用户没有提供具体的,要根据前后信息记录大概时间。
|
||||
@@ -12,5 +12,5 @@
|
||||
|
||||
## 维护规范
|
||||
- 文件内容使用 UTF-8 编码
|
||||
- 每次写入时,将新内容与已有记忆合并整理后再保存
|
||||
- 为保护用户隐私,除非用户询问自己的健康或医疗相关资料,否则/memories/user_memory.txt里的信息不轻易输出给用户。
|
||||
- 每次保存时,先把新信息与已有记忆整理成完整的记忆内容,再用 `write_file` 一次性整体重写 `/memories/memory.txt`(write_file 支持整文件覆盖,无需先读后改或多次编辑)
|
||||
- 为保护用户隐私,除非用户询问自己的健康或医疗相关资料,否则/memories/memory.txt里的信息不轻易输出给用户。
|
||||
@@ -6,18 +6,20 @@ import { ChatOpenAI } from "@langchain/openai";
|
||||
import { AIMessageChunk, ToolMessage } from "langchain";
|
||||
import { HumanMessage } from "@langchain/core/messages";
|
||||
import { ChatDeepSeek } from "@langchain/deepseek";
|
||||
import config from '../../conf.json' with { type: 'json' };
|
||||
import logger from '../../utils/logger.js';
|
||||
import config from '../../../conf.json' with { type: 'json' };
|
||||
import logger from '../../../utils/logger.js';
|
||||
|
||||
// 密钥由 conf.json 统一提供;百度地图 skill 通过 env_get 读环境变量,此处桥接
|
||||
process.env.TAVILY_API_KEY ??= config.agent.tavily?.apiKey;
|
||||
process.env.BAIDU_MAP_AUTH_TOKEN ??= config.agent.baiduMap?.authToken;
|
||||
import Prompts from "./prompts.js";
|
||||
import { createRestrictedBackend } from "../../infra/restricted_fs_backend.js";
|
||||
import { createHospitalInfoSubagent } from "../../subagent/hospital_info.js";
|
||||
import {
|
||||
getEnvTool, webFetchTool, webSearchTool, getCalendarInfoTool,
|
||||
getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool, getLatLngTool,
|
||||
httpGetTool, httpPostTool, createEscortRecordQueryTool
|
||||
} from "./tools/index.js";
|
||||
} from "../../infra/tools/index.js";
|
||||
|
||||
export default class EscortAgent {
|
||||
// 历史消息字符数上限,超出时从头部丢弃完整轮次
|
||||
@@ -144,8 +146,10 @@ export default class EscortAgent {
|
||||
|
||||
_genAgent(userInfo) {
|
||||
const rootDir = process.cwd();
|
||||
// 外部数据(用户记忆等)存储目录,由 conf.json agent.dataDir 配置
|
||||
const dataDir = path.resolve(rootDir, config.agent.dataDir ?? "data");
|
||||
const memoryFile = userInfo
|
||||
? path.join(rootDir, "data", userInfo._id, "memories", "user_memory.txt")
|
||||
? path.join(dataDir, "users", userInfo._id, "memory.txt")
|
||||
: null;
|
||||
|
||||
// 会话中记忆文件被更新后重建 agent,使 systemPrompt 中的用户记忆保持最新
|
||||
@@ -156,15 +160,17 @@ export default class EscortAgent {
|
||||
return this.agent;
|
||||
}
|
||||
|
||||
let backend = new FilesystemBackend({ rootDir });
|
||||
// 受限后端:锁定沙箱根并禁止读取 conf.json/.env/logs 及用户数据目录
|
||||
let backend = createRestrictedBackend({ rootDir, dataDir });
|
||||
|
||||
if (userInfo) {
|
||||
const userMemoryPath = path.join(rootDir, "data", userInfo._id, "memories");
|
||||
// 挂载根为用户数据目录:/memories/memory.txt ↔ data/users/{userId}/memory.txt
|
||||
const userMemoryRoot = path.join(dataDir, "users", userInfo._id);
|
||||
backend = new CompositeBackend(
|
||||
new FilesystemBackend({ rootDir }),
|
||||
createRestrictedBackend({ rootDir, dataDir }),
|
||||
{
|
||||
"/memories/": new FilesystemBackend({
|
||||
rootDir: userMemoryPath,
|
||||
rootDir: userMemoryRoot,
|
||||
virtualMode: true
|
||||
})
|
||||
},
|
||||
@@ -183,12 +189,13 @@ export default class EscortAgent {
|
||||
name: "deep-agent",
|
||||
model: this.flashModel,
|
||||
systemPrompt: Prompts.buildSystemPrompt(userInfo),
|
||||
memory: ["./agent/escort/AGENTS.md"],
|
||||
memory: ["./agent/bots/bot-escort/AGENTS.md"],
|
||||
backend,
|
||||
tools: [getEnvTool, webFetchTool, webSearchTool, getLatLngTool, httpGetTool, httpPostTool,
|
||||
getCalendarInfoTool, getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool,
|
||||
createEscortRecordQueryTool(userInfo)],
|
||||
skills: ["./agent/escort/skills/"],
|
||||
subagents: [createHospitalInfoSubagent(this.flashModel)],
|
||||
skills: ["./agent/infra/skills/"],
|
||||
});
|
||||
|
||||
return this.agent;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import services from "../../resource/services.js";
|
||||
import agreement from "../../resource/agreement.js";
|
||||
import logger from "../../utils/logger.js";
|
||||
import config from "../../../conf.json" with { type: 'json' };
|
||||
import services from "../../../resource/services.js";
|
||||
import agreement from "../../../resource/agreement.js";
|
||||
import logger from "../../../utils/logger.js";
|
||||
|
||||
class Prompts {
|
||||
static buildSystemPrompt(userInfo) {
|
||||
@@ -19,8 +20,8 @@ class Prompts {
|
||||
address: userInfo.addresses || [],
|
||||
});
|
||||
|
||||
const rootDir = process.cwd();
|
||||
const userMemoryPath = path.join(rootDir, "data", userInfo._id, "memories", "user_memory.txt");
|
||||
const dataDir = path.resolve(process.cwd(), config.agent.dataDir ?? "data");
|
||||
const userMemoryPath = path.join(dataDir, "users", userInfo._id, "memory.txt");
|
||||
try {
|
||||
usermem_str = fs.readFileSync(userMemoryPath, 'utf8');
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user