feat:完成重构和测试
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
"""会话历史:数据库保存完整对话,每次请求按 token 预算只带最近的完整轮次
|
||||
|
||||
裁剪在服务层组装请求时做一次,意图判断、问答和 screen agent 看到的是同一段历史
|
||||
"""
|
||||
|
||||
from langchain_core.messages import (
|
||||
AIMessage,
|
||||
BaseMessage,
|
||||
HumanMessage,
|
||||
trim_messages,
|
||||
)
|
||||
from langchain_core.messages.utils import count_tokens_approximately
|
||||
|
||||
from app.schemas.base import JsonObject
|
||||
|
||||
|
||||
def history_messages(history: list[JsonObject]) -> list[BaseMessage]:
|
||||
"""每轮转成一条用户消息和一条助手消息,按时间从早到晚排列"""
|
||||
messages: list[BaseMessage] = []
|
||||
for turn in history:
|
||||
messages.append(HumanMessage(content=turn["user"]))
|
||||
messages.append(AIMessage(content=turn["assistant"]))
|
||||
return messages
|
||||
|
||||
|
||||
def trim_history(history: list[JsonObject], max_tokens: int) -> list[JsonObject]:
|
||||
"""从最近一轮往前保留,总量不超过 max_tokens;只保留完整的轮次,不从一段回复中间截断
|
||||
|
||||
单独一轮就超过预算时这一轮也不保留
|
||||
"""
|
||||
kept = trim_messages(
|
||||
history_messages(history),
|
||||
max_tokens=max_tokens,
|
||||
token_counter=count_tokens_approximately,
|
||||
strategy="last",
|
||||
# 从用户消息开始,助手回复放不下时连同它的用户消息一起去掉
|
||||
start_on="human",
|
||||
)
|
||||
return history[len(history) - len(kept) // 2 :]
|
||||
@@ -14,8 +14,10 @@ class IntentNode(BaseNode):
|
||||
|
||||
async def process(self, state: QueryState) -> QueryState:
|
||||
updated_state: QueryState = state.copy()
|
||||
context = state["input_context"]
|
||||
request = DecisionRequest(
|
||||
state=request_summary(state["input_context"]),
|
||||
# Jev 只接收 JSON,会话历史作为 history 字段和本次请求放在一起
|
||||
state={"history": context.history, **request_summary(context)},
|
||||
decisions={"intent": build_intent_question()},
|
||||
)
|
||||
response = await get_decision_engine().run(request)
|
||||
|
||||
@@ -6,6 +6,7 @@ from langgraph.config import get_stream_writer
|
||||
|
||||
from app.clients.llm import get_llm
|
||||
from app.processor.base import BaseNode
|
||||
from app.processor.history import history_messages
|
||||
from app.processor.state import QueryState
|
||||
from app.prompt.qa import QA_SYSTEM_PROMPT
|
||||
|
||||
@@ -24,11 +25,16 @@ class QANode(BaseNode):
|
||||
|
||||
parser = StrOutputParser()
|
||||
parts: list[str] = []
|
||||
context = state["input_context"]
|
||||
async for chunk in get_llm().astream(
|
||||
[
|
||||
SystemMessage(content=QA_SYSTEM_PROMPT),
|
||||
# 会话历史作为此前的对话消息,本次请求是最后一条用户消息
|
||||
*history_messages(context.history),
|
||||
HumanMessage(
|
||||
content=state["input_context"].model_dump_json(exclude_unset=True)
|
||||
content=context.model_dump_json(
|
||||
exclude_unset=True, exclude={"history"}
|
||||
)
|
||||
),
|
||||
]
|
||||
):
|
||||
|
||||
@@ -10,6 +10,7 @@ from langchain_core.messages import HumanMessage
|
||||
from app.agent.screen_agent import AgentReply, get_screen_agent
|
||||
from app.agent.tools import ScreenAgentContext
|
||||
from app.processor.base import BaseNode
|
||||
from app.processor.history import history_messages
|
||||
from app.processor.state import QueryState
|
||||
from app.processor.summary import request_summary
|
||||
from app.resources.component import get_catalog_cache
|
||||
@@ -55,10 +56,12 @@ class ScreenAgentNode(BaseNode):
|
||||
agent = await get_screen_agent()
|
||||
result = await agent.ainvoke(
|
||||
{
|
||||
# 会话历史作为此前的对话消息,本次请求是最后一条用户消息
|
||||
"messages": [
|
||||
*history_messages(context.history),
|
||||
HumanMessage(
|
||||
content=json.dumps(request_summary(context), ensure_ascii=False)
|
||||
)
|
||||
),
|
||||
]
|
||||
},
|
||||
context=ScreenAgentContext(screen=context.screen, catalog=catalog),
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
"""请求摘要:意图判断和 screen agent 共用,只给组件的识别信息和布局,完整配置按需读取"""
|
||||
"""请求摘要:意图判断和 screen agent 共用,只给组件的识别信息和布局,完整配置按需读取
|
||||
|
||||
只描述本次请求;会话历史由各使用方另行传入,见 history.py
|
||||
"""
|
||||
|
||||
from app.schemas.base import JsonObject
|
||||
from app.schemas.input_context import InputContext
|
||||
|
||||
|
||||
def request_summary(context: InputContext) -> JsonObject:
|
||||
"""用户输入、会话历史、澄清记录、编辑上下文、附件和大屏摘要"""
|
||||
"""用户输入、澄清记录、编辑上下文、附件和大屏摘要"""
|
||||
nodes: list[JsonObject] = []
|
||||
for node in context.screen.nodes:
|
||||
# 图表标题帮助判断用户指的是哪个组件;没有 option 或标题格式不符时按无标题处理
|
||||
@@ -28,7 +31,6 @@ def request_summary(context: InputContext) -> JsonObject:
|
||||
|
||||
return {
|
||||
"prompt": context.prompt,
|
||||
"history": context.history,
|
||||
"clarification_history": context.clarification_history,
|
||||
"context": context.context.model_dump(mode="json", exclude_unset=True),
|
||||
"screen_summary": {
|
||||
|
||||
Reference in New Issue
Block a user