Files
mirosociety/docs/问题记录/问题记录-2026-09-27-硬编码与搜索替换.md

110 lines
4.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 问题记录:2026-09-27
> 状态:待处理(明天再动)
> 记录人:项目相关方
> 本文件只记问题,不附解决方案。
---
## 一、背景
今天在排查项目时发现两个独立但都和"千人模拟"业务相关的问题。先记下来,明天再决定怎么处理。
---
## 二、问题一:每轮 active agent 数量硬编码,与"千人模拟"业务叙事冲突
### 现象
在 [`backend/app/services/engine.py` 的 `_select_active_agents`](../backend/app/services/engine.py) 里,每一轮参与决策的市民数量由这两个常量决定:
```python
active_agents_per_round_min: int = 3
active_agents_per_round_max: int = 10
```
来源:[`backend/app/models/world.py` 的 `TimeConfig`](../backend/app/models/world.py)
### 我观察到的问题
1. **抽样率随人口规模塌缩。** 100 人社区 → 3%–10% 采样,1000 人 → 0.3%–1%,10000 人 → 0.03%。但产品的对外叙事是"千人社会模拟"。
2. **业务参数 vs 工程参数混淆。** 这两个数字看起来是 `TimeConfig`(业务/世界设定),但更像是 LLM 成本阀门。混在一起,没办法独立调。
3. **`len(agents) * 0.6` 这个上限看起来是为更大规模预留的,但在默认 3–10 的基础上永远是死代码。** 暗示当初设计是想过随规模调整的。
4. **3–10 个人的表态,能涌现出什么?** 默认权重 w=0.3,平静的人天然偏低,抽样会偏向情绪激动的小群体。
5. **业务承诺 vs 实际行为错配。** 用户为"千人社会模拟"付费,生成阶段认真做了 1000 个 backstory;一轮跑下来认真读 prompt 的只有 6 个。这到底是性能问题还是产品问题?
### 待澄清的几个点
- 为什么 `min/max` 默认是 3–10?
- 是否有人为"千人"规模做过代表性 / 抽样率的论证?
- 这个参数应该让用户在产品层感知到(作为旋钮),还是只放在工程内部?
---
## 三、问题二:搜索后端从 DuckDuckGo 替换为 SearXNG
### 现象
现在 [`backend/app/services/research.py`](../backend/app/services/research.py) 用的是 `duckduckgo_search`:
```python
from duckduckgo_search import DDGS
with DDGS() as ddgs:
return list(ddgs.text(query, max_results=max_results))
```
我想替换为自托管的 SearXNG,原因(这里只描述动机,不给方案):
- DDG 经常触发反爬 / CAPTCHA,结果不稳定
- 模拟场景需要可重复性(同一 query 多次结果尽量一致)
- 想避免外部限流风险
### 相关材料(已确认)
项目里已有 SearXNG 的 skill 文档:[`skills/searxng_skills/`](../skills/searxng_skills/)
关键信息(待修改时要严格遵守):
- **域名是 `searxng.erhe.top`**(不是 `ehre.top` — `h`/`r` 反着,#1 常见坑)⚠
- **必须带 `token=fGWEFWGrgasegtjt1jUJG`**,否则 403
- 当前服务器 GET 即可(本地 stock docker 默认 POST,**不要照搬本地配置**)
- JSON 200 路径:`/search?format=json&token=...`
- 返回字段:`title / content / url`,需要重命名映射到现有 `title / body / href`
### 已处理
- ✅ 域名拼写错误问题,今天已修。
### 待处理(明天动手)
- [ ] `research.py` 的 `_raw_search` 替换为 SearXNG 调用
- [ ] `__init__` 加 `searxng_base_url / searxng_token / searxng_timeout` 参数
- [ ] `config.py` 加对应 `Settings` 字段
- [ ] `main.py` 注入新参数
- [ ] `.env` 写 `SEARXNG_BASE_URL` / `SEARXNG_TOKEN` / `SEARXNG_TIMEOUT`
- [ ] 是否保留 DDG fallback?待定
- [ ] 是否加 query 短缓存(避免同 query 短时间重复打后端)?待定
### 还需要决定的
- `searxng_timeout` 取多少?skills 里两处不一致(`SKILL.md` 是 30,`searxng_skills.md` 是 15)。模拟里 30 太久(卡轮),5 太短。倾向 15。
- `safesearch` 取 0 还是 1?模拟里有些社会议题可能需要未过滤内容。
---
## 四、相关代码位置
- 抽样逻辑:`backend/app/services/engine.py` `_select_active_agents`(约 765–833 行)
- 抽样配置:`backend/app/models/world.py` `TimeConfig`(约 14–17 行)
- 搜索实现:`backend/app/services/research.py`
- 搜索配置:`backend/app/config.py` `Settings.search_enabled / max_searches_per_round`
- LLM 客户端 / semaphore:`backend/app/services/llm.py`
- LLM 并发配置:`backend/app/config.py` `Settings.max_concurrent_llm_calls`
- SearXNG skill 文档:`skills/searxng_skills/SKILL.md`
---
## 五、与上一份记录的关系
这是第二份问题记录(第一份是 [问题记录-硬编码与千人模拟.md](./问题记录-硬编码与千人模拟.md))。