Commit 50fcfb9d6eb522e6656ddc551146b17d7eb4b23b

Authored by tangwang
1 parent 7e985858

up

COMMIT_MSG.txt 0 → 100644
README_prompts.md
... ... @@ -71,3 +71,16 @@ graphRAG在商品搜索中如何使用?我想将他用于,对商品的模糊
71 71 2. 一个勾选框,点击后为勾选状态。可以勾选多个商品。
72 72 下方也悬浮两个菜单,一个ask,一个compare。
73 73 如果是点击了ask,那么,将引用这两个商品进行继续对话,如果点击了compare,那么,也是从右侧拉出一个页面,覆盖到上面,对这两个商品进行对比,页面内容为空,提示暂未实现即可)
  74 +
  75 +
  76 +
  77 +
  78 +
  79 +
  80 +
  81 +
  82 +
  83 +
  84 +要持久化session,每一次对话都要保存起来,左侧例举出来,点击其中一个就可以继续进行对话。
  85 +2. 现在用户的对话,和AI的回复,差别不明显,比如一个靠做一个靠右?请你思考一个简单的做法,然后 用户的发言,是可编辑的,也就是,之前的某个轮次,用户输入框的内容可以修改,修改后点击发送,则从这个地方开始对话、原来的这里之后的内容就清空(覆盖)掉了
  86 +如何设计比较好
74 87 \ No newline at end of file
... ...
... ... @@ -516,7 +516,7 @@ def _run_similar_search(query: str) -> Optional[str]:
516 516 return None
517 517 tool = make_search_products_tool(session_id, global_registry)
518 518 try:
519   - out = tool.invoke({"query": query.strip(), "limit": 12})
  519 + out = tool.invoke({"query": query.strip()})
520 520 match = SEARCH_REF_PATTERN.search(out)
521 521 if match:
522 522 return match.group(1).strip()
... ... @@ -608,7 +608,7 @@ def display_product_card_from_item(
608 608  
609 609 def render_search_result_block(result: SearchResult, widget_prefix: str = "") -> None:
610 610 """
611   - Render a full search result block in place of a [SEARCH_REF:xxx] token.
  611 + Render a full search result block in place of a [SEARCH_REF:ref_id] token.
612 612  
613 613 widget_prefix: unique per (message, ref block) so Streamlit widget keys stay unique.
614 614 """
... ... @@ -649,7 +649,7 @@ def render_message_with_refs(
649 649 msg_index: int = 0,
650 650 ) -> None:
651 651 """
652   - Render an assistant message that may contain [SEARCH_REF:xxx] tokens.
  652 + Render an assistant message that may contain [SEARCH_REF:ref_id] tokens.
653 653  
654 654 msg_index: message index in chat, used to keep widget keys unique across messages.
655 655 """
... ... @@ -730,7 +730,7 @@ def display_message(message: dict, msg_index: int = 0):
730 730  
731 731 st.markdown("---")
732 732  
733   - # Render message: expand [SEARCH_REF:xxx] tokens into product card blocks
  733 + # Render message: expand [SEARCH_REF:ref_id] tokens into product card blocks
734 734 session_id = st.session_state.get("session_id", "")
735 735 render_message_with_refs(
736 736 content, session_id, fallback_refs=message.get("search_refs"), msg_index=msg_index
... ...
app/agents/shopping_agent.py
... ... @@ -4,7 +4,7 @@ Conversational Shopping Agent with LangGraph
4 4 Architecture:
5 5 - ReAct-style agent: plan → search → evaluate → re-plan or respond
6 6 - search_products is session-bound, writing curated results to SearchResultRegistry
7   -- Final AI message references results via [SEARCH_REF:xxx] tokens instead of
  7 +- Final AI message references results via [SEARCH_REF:ref_id] tokens instead of
8 8 re-listing product details; the UI renders product cards from the registry
9 9 """
10 10  
... ... @@ -34,7 +34,7 @@ logger = logging.getLogger(__name__)
34 34 # Key design decisions:
35 35 # 1. Guides multi-query search planning with explicit evaluate-and-decide loop
36 36 # 2. Forbids re-listing product details in the final response
37   -# 3. Mandates [SEARCH_REF:xxx] inline citation as the only product presentation mechanism
  37 +# 3. Mandates [SEARCH_REF:ref_id] inline citation as the only product presentation mechanism
38 38 SYSTEM_PROMPT = f"""角色定义
39 39 你是我们店铺的一名专业的电商导购,是一个善于倾听、主动引导、懂得搭配的“时尚顾问”,通过有温度的对话,给用户提供有价值的信息,包括需求引导、方案推荐、搜索结果推荐,最终促成满意的购物决策或转化行为。
40 40 作为我们店铺的一名专业的销售,除了本店铺的商品的推荐,你可以给用户提供有帮助的信息,但是不要虚构商品、提供本商店搜索结果以外的商品。
... ... @@ -52,9 +52,9 @@ SYSTEM_PROMPT = f"""角色定义
52 52 2. 如何使用make_search_products_tool:
53 53 1. 可以生成多个query进行搜索:在需要搜索商品的时候,可以将需求分解为 2-4 个搜索查询,每个 query 聚焦一个明确的商品子类或搜索角度。
54 54 2. 可以根据搜索结果调整搜索策略:每次调用 search_products 后,工具会返回搜索结果的相关性的判断、以及搜索结果的topN的title,你需要决策是否要调整搜索策略,比如结果质量太差,可能需要调整搜索词、或者加大试探的query数量(不要超过3-5个)。结果太差的原因有可能是你生成的query不合理、请根据你看到的商品名称的构成组织搜索关键词。
55   -3. 在最终回复中使用 [SEARCH_REF:xxx] 内联引用搜索结果:
56   - 1. 搜索工具会返回一个结果引用标识[SEARCH_REF:xxx],撰写最终答复的时候请直接引用 [SEARCH_REF:xxx] ,系统会自动在该位置渲染对应的商品卡片列表,无需复述搜索结果。
57   - 2. 因为系统会自动将[SEARCH_REF:xxx]渲染为搜索结果,所以[SEARCH_REF:xxx]必须独占一行,且只在需要渲染该query完整的搜索结果时才进行引用,同一个结果不要重复引用。
  55 +3. 在最终回复中使用 [SEARCH_REF:ref_id] 内联引用搜索结果:
  56 + 1. 搜索工具会返回一个结果引用标识[SEARCH_REF:ref_id],撰写最终答复的时候请直接引用 [SEARCH_REF:ref_id] ,系统会自动在该位置渲染对应的商品卡片列表,无需复述搜索结果。
  57 + 2. 因为系统会自动将[SEARCH_REF:ref_id]渲染为搜索结果,所以[SEARCH_REF:ref_id]必须独占一行,且只在需要渲染该query完整的搜索结果时才进行引用,同一个结果不要重复引用。
58 58 4. 今天是{datetime.now().strftime("%Y-%m-%d")},所有与当前时间(比如天气、最新或即将发生的事件)相关的问题,都要使用web_search工具)。
59 59 """
60 60  
... ... @@ -72,8 +72,8 @@ SYSTEM_PROMPT___2 = """ 角色定义
72 72 2. 如何使用make_search_products_tool:
73 73 1. 可以生成多个query进行搜索:在需要搜索商品的时候,可以将需求分解为 2-4 个搜索查询,每个 query 聚焦一个明确的商品子类或搜索角度。
74 74 2. 可以根据搜索结果调整搜索策略:每次调用 search_products 后,工具会返回搜索结果的相关性的判断、以及搜索结果的topN的title,你需要决策是否要调整搜索策略,比如结果质量太差,可能需要调整搜索词、或者加大试探的query数量(不要超过3-5个)。
75   - 3. 使用 [SEARCH_REF:xxx] 内联引用搜索结果:搜索工具会返回一个结果引用标识[SEARCH_REF:xxx],撰写最终答复的时候可以直接引用将 [SEARCH_REF:xxx] ,系统会自动在该位置渲染对应的商品卡片列表,无需复述搜索结果。
76   - 4. 因为系统会自动将[SEARCH_REF:xxx]渲染为搜索结果,所以只在需要渲染该query完整的搜索结果时才进行引用,同一个结果不要重复引用。
  75 + 3. 使用 [SEARCH_REF:ref_id] 内联引用搜索结果:搜索工具会返回一个结果引用标识[SEARCH_REF:ref_id],撰写最终答复的时候可以直接引用将 [SEARCH_REF:ref_id] ,系统会自动在该位置渲染对应的商品卡片列表,无需复述搜索结果。
  76 + 4. 因为系统会自动将[SEARCH_REF:ref_id]渲染为搜索结果,所以只在需要渲染该query完整的搜索结果时才进行引用,同一个结果不要重复引用。
77 77 """
78 78  
79 79  
... ... @@ -226,7 +226,7 @@ class ShoppingAgent:
226 226  
227 227 Returns:
228 228 dict with keys:
229   - response – final AI message text (may contain [SEARCH_REF:xxx] tokens)
  229 + response – final AI message text (may contain [SEARCH_REF:ref_id] tokens)
230 230 tool_calls – list of {name, args, result_preview}
231 231 debug_steps – detailed per-node step log
232 232 search_refs – dict[ref_id → SearchResult] for all searches this turn
... ...
app/config.py
... ... @@ -43,6 +43,8 @@ class Settings(BaseSettings):
43 43 # Search Configuration
44 44 top_k_results: int = 10
45 45 similarity_threshold: float = 0.6
  46 + # 商品搜索 API 单次请求最多返回条数(1–20),search_products 统一使用此配置
  47 + search_products_limit: int = 20
46 48  
47 49 # Search API (see docs/搜索API对接指南.md)
48 50 search_api_base_url: str = "http://120.76.41.98:6002"
... ...
app/search_registry.py
... ... @@ -2,7 +2,7 @@
2 2 Search Result Registry
3 3  
4 4 Stores structured search results keyed by session and ref_id.
5   -Each [SEARCH_REF:xxx] in an AI response maps to a SearchResult stored here,
  5 +Each [SEARCH_REF:ref_id] in an AI response maps to a SearchResult stored here,
6 6 allowing the UI to render product cards without the LLM ever re-listing them.
7 7 """
8 8  
... ...
app/tools/search_tools.py
... ... @@ -82,7 +82,15 @@ def _assess_search_quality(query: str, raw_products: list) -> tuple[list[str], s
82 82 搜索结果(共 {n} 条):
83 83 {product_text}
84 84  
85   -等级说明:Relevant=完全符合查询意图;Partially Relevant=基本相关(如品类等主需求匹配但部分属性不完全符合);Irrelevant=不相关。
  85 +等级说明:
  86 +Relevant
  87 +The product generally satisfies the main shopping intent of the query. Minor missing, implicit, or unspecified attributes are acceptable as long as the product reasonably fits the intended use or scenario.
  88 +
  89 +Partially Relevant
  90 +The product is related to the query and matches the general category or purpose, but shows weaker alignment with the specific intent or context.
  91 +
  92 +Irrelevant
  93 +The product does not match the core intent or intended use implied by the query.
86 94  
87 95 请严格按以下 JSON 输出,仅输出 JSON,无其他内容:
88 96 {{"labels": ["Relevant", "Partially Relevant", "Irrelevant", ...], "quality_summary": "你的1-2句总结"}}
... ... @@ -132,17 +140,17 @@ def make_search_products_tool(
132 140 """
133 141  
134 142 @tool
135   - def search_products(query: str, limit: int = 20) -> str:
  143 + def search_products(query: str) -> str:
136 144 """搜索商品库并做质量评估:LLM 为每条结果打等级(Relevant / Partially Relevant / Irrelevant),返回引用与 top10 标题。
137 145  
138 146 Args:
139 147 query: 自然语言商品描述
140   - limit: 最多返回条数(1-20)
141 148  
142 149 Returns:
143 150 【搜索完成】+ 结果引用 [SEARCH_REF:ref_id] + 质量情况(评估条数、Relevant/Partially Relevant 数)+ results list(top10 标题)
144 151 """
145 152 try:
  153 + limit = min(max(settings.search_products_limit, 1), 20)
146 154 logger.info(f"[{session_id}] search_products: query={query!r} limit={limit}")
147 155  
148 156 url = f"{settings.search_api_base_url.rstrip('/')}/search/"
... ... @@ -152,7 +160,7 @@ def make_search_products_tool(
152 160 }
153 161 payload = {
154 162 "query": query,
155   - "size": min(max(limit, 1), 20),
  163 + "size": limit,
156 164 "from": 0,
157 165 "language": "zh",
158 166 "enable_rerank": True,
... ...