1. 项目概述:AI商业顾问应用开发全流程
作为一名长期从事AI应用开发的工程师,我发现很多初学者在构建LLM应用时容易陷入两个极端:要么停留在简单的API调用层面,要么被复杂的架构设计吓退。这个AI商业顾问项目恰好填补了中间地带的空白,它展示了一个真实可用的商业级应用该有的完整形态。
这个项目的核心价值在于:
- 采用生产环境常用的模块化架构设计(LLM接口层、工具层、会话管理层)
- 整合了商业分析场景中最实用的两大能力:实时数据获取(搜索API)和专业分析框架(提示工程)
- 通过Streamlit实现了开箱即用的可视化界面,避免了前端开发的复杂性
我特别欣赏项目中工具链的选择:智谱AI提供性价比优异的国产大模型,Tavily Search则是专为AI优化的搜索引擎,这种组合既保证了能力又控制了成本。下面我将拆解这个项目的技术实现,并分享我在类似项目中的实战经验。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心架构设计解析
2.1 模块化设计原则
项目的目录结构体现了清晰的职责划分:
code复制ai_consultant_agent/
├── app.py # 界面逻辑
├── llm_provider.py # 模型抽象层
├── tools/ # 能力组件
│ ├── web_search.py # 实时数据获取
│ ├── market_analysis.py # 专业分析引擎
│ └── strategy.py # 决策建议生成
├── utils/
│ └── session.py # 对话状态管理
这种架构的优势在于:
- 可维护性:每个模块的变更不会影响其他组件
- 可扩展性:新增工具只需在tools目录添加新文件
- 可测试性:每个模块可以独立进行单元测试
实际开发中,我建议在tools目录下再细分domain目录(如finance/、marketing/),当业务分析维度增多时能保持更好的组织性。
2.2 LLM接口抽象层
llm_provider.py 的设计体现了重要的工程思维 - 依赖倒置。通过统一的接口封装不同LLM提供商的差异,这带来了三个关键好处:
- 切换成本低:更换模型只需修改配置参数
- 功能一致性:无论底层API如何变化,上层应用调用方式不变
- 容错增强:可以在抽象层统一处理限流、重试等机制
我对其进行了增强实现:
python复制class LLMProvider:
def __init__(self, provider="zhipu", model="glm-4-flash"):
self.provider = provider
self.model = model
self._init_client() # 根据provider初始化对应客户端
def _init_client(self):
if self.provider == "zhipu":
from zhipuai import ZhipuAI
self.client = ZhipuAI(api_key=os.getenv("ZHIPU_API_KEY"))
elif self.provider == "openai":
from openai import OpenAI
self.client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# 可扩展其他提供商
def chat(self, messages, temperature=0.7, max_retries=3):
for attempt in range(max_retries):
try:
if self.provider == "zhipu":
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
temperature=temperature
)
return response.choices[0].message.content
# 其他提供商处理...
except Exception as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt) # 指数退避
关键增强点:
- 多提供商支持(通过环境变量切换)
- 自动重试机制(应对API不稳定)
- 统一的响应格式处理
3. 关键技术实现细节
3.1 实时数据获取方案
web_search.py 中Tavily Search的集成有几个精妙设计:
- 结果缓存:避免重复查询相同内容
- 结构化返回:将原始HTML转换为易处理的对象
- 相关性过滤:只保留高置信度的结果
我的优化版本增加了结果后处理:
python复制class EnhancedTavilySearch(TavilySearch):
def search(self, query, max_results=5, min_relevance=0.7):
# 检查缓存
cache_key = f"{query}-{max_results}"
if cached := self._check_cache(cache_key):
return cached
# 执行搜索
raw_results = self._client.search(
query=query,
max_results=max_results*2 # 超量获取用于过滤
)
# 结果处理
processed = []
for item in raw_results["results"]:
if item["score"] < min_relevance:
continue
processed.append(SearchResult(
title=self._clean_text(item["title"]),
url=item["url"],
content=self._summarize(item["content"]),
published=datetime.strptime(item["published"], "%Y-%m-%d")
))
# 缓存处理后的结果
self._cache_results(cache_key, processed[:max_results])
return processed[:max_results]
实际使用中发现,添加发布日期过滤(如只保留1年内的内容)能显著提升商业分析的新鲜度。
3.2 提示工程实践
market_analysis.py 中的提示模板有几个值得学习的点:
- 角色明确:"你是一个专业的市场分析师"
- 结构化输出:指定JSON格式和具体分析维度
- 上下文注入:动态插入搜索结果的策略
我常用的增强技巧包括:
- 少样本学习:在提示词中包含1-2个完整分析示例
- 链式思考:要求模型先列出分析步骤再输出结果
- 格式校验:在代码中验证返回的JSON结构
优化后的提示模板:
python复制ANALYSIS_PROMPT = """你是一个拥有10年经验的市场分析专家,擅长为科技初创公司提供建议。
请根据以下信息为{query}进行分析:
行业背景:
{industry}
参考数据:
{search_context}
分析框架:
1. 市场规模(估算当前价值和增长率)
2. 竞争格局(列出TOP3竞争者及其市占率)
3. 用户画像(核心用户群体及需求)
4. 技术趋势(影响该领域的新兴技术)
5. 风险预警(政策、市场、技术风险)
请严格按以下JSON格式返回:
{
"market_size": {"value": "", "growth_rate": ""},
"competitors": [{"name": "", "advantage": ""}],
"user_segments": [{"type": "", "pain_points": ""}],
"tech_trends": [],
"risks": []
}
示例参考:
{examples} # 此处插入1-2个完整分析案例
"""
4. 会话管理的工程实现
session.py 的会话管理看似简单,实则包含多个关键设计:
4.1 上下文窗口控制
为避免超过模型token限制,需要实现智能的上下文截断:
python复制def get_context_messages(self, max_tokens=4000):
total = 0
selected = []
# 逆序遍历,优先保留最新消息
for msg in reversed(self.messages):
msg_tokens = len(msg["content"]) // 3 # 简单估算
if total + msg_tokens > max_tokens:
break
selected.append(msg)
total += msg_tokens
return list(reversed(selected)) # 恢复时序
4.2 多模态会话支持
扩展会话对象以支持文件等附件:
python复制class SessionMessage:
def __init__(self, role, content, attachments=None):
self.role = role
self.content = content
self.attachments = attachments or []
self.timestamp = datetime.now()
class EnhancedSessionManager(SessionManager):
def add_message(self, role, content, files=None):
msg = SessionMessage(role, content, files)
self.messages.append(msg)
def get_recent_files(self, n=3):
return [
f for msg in reversed(self.messages)
for f in msg.attachments
][:n]
4.3 持久化方案
将会话保存到数据库的推荐实现:
python复制def save_to_db(self, session_id):
record = {
"session_id": session_id,
"messages": [msg.__dict__ for msg in self.messages],
"search_cache": [
{"query": k, "results": v}
for k,v in self.search_cache.items()
],
"updated_at": datetime.now()
}
# MongoDB示例
db.sessions.update_one(
{"session_id": session_id},
{"$set": record},
upsert=True
)
5. Streamlit界面的专业优化
原始app.py提供了基础功能,但生产环境还需要:
5.1 页面布局优化
python复制def setup_ui():
st.set_page_config(
page_title="商业顾问Pro",
layout="wide",
initial_sidebar_state="expanded"
)
# 自定义CSS
st.markdown("""
<style>
.stTextInput input {border-radius: 10px;}
.stButton button {background: #4CAF50 !important;}
div[data-testid="stExpander"] div {padding: 1rem;}
</style>
""", unsafe_allow_html=True)
# 响应式布局
col1, col2 = st.columns([3, 1])
return col1, col2
5.2 分析历史可视化
python复制def show_history():
if "history" not in st.session_state:
st.session_state.history = []
with st.sidebar.expander("📈 分析趋势"):
history_df = pd.DataFrame(st.session_state.history)
if not history_df.empty:
history_df["date"] = pd.to_datetime(history_df["timestamp"])
by_date = history_df.groupby(history_df["date"].dt.date).size()
st.area_chart(by_date)
with st.sidebar.expander("🔍 最近查询"):
for idx, item in enumerate(reversed(st.session_state.history[-5:])):
if st.button(f"{idx+1}. {item['query'][:15]}..."):
st.session_state.current_query = item["query"]
5.3 结果呈现增强
python复制def display_analysis(result):
tabs = st.tabs(["市场概览", "竞争分析", "用户画像", "风险预警"])
with tabs[0]:
col1, col2 = st.columns(2)
col1.metric("市场规模", result["market_size"]["value"])
col2.metric("年增长率", result["market_size"]["growth_rate"])
with tabs[1]:
for competitor in result["competitors"]:
with st.expander(competitor["name"]):
st.progress(competitor["market_share"] / 100)
st.write(competitor["advantage"])
# 其他标签页内容...
6. 生产环境部署方案
6.1 Docker化部署
Dockerfile 最佳实践:
dockerfile复制FROM python:3.9-slim
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt \
&& apt-get update \
&& apt-get install -y --no-install-recommends gcc python3-dev \
&& rm -rf /var/lib/apt/lists/*
ENV STREAMLIT_SERVER_PORT=8501
EXPOSE 8501
CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
配套的docker-compose.yml:
yaml复制version: '3.8'
services:
consultant:
build: .
ports:
- "8501:8501"
env_file:
- .env
volumes:
- ./data:/app/data # 持久化会话数据
restart: unless-stopped
6.2 性能优化技巧
- 缓存机制:
python复制@st.cache_resource(ttl=3600)
def get_llm_provider():
return LLMProvider()
@st.cache_data(ttl=600)
def cached_search(query):
return search_tool.search(query)
- 异步处理:
python复制async def async_analysis(query):
search_results = await asyncio.to_thread(search_tool.search, query)
analysis = await llm.chat_async(prepare_prompt(query, search_results))
return analysis
- 负载监控:
python复制from prometheus_client import start_http_server, Counter
REQUESTS = Counter('app_requests', 'Total API requests')
ERRORS = Counter('app_errors', 'Total errors')
def monitor(func):
def wrapper(*args, **kwargs):
REQUESTS.inc()
try:
return func(*args, **kwargs)
except Exception:
ERRORS.inc()
raise
return wrapper
7. 避坑指南与经验分享
7.1 API调用常见问题
问题1:响应时间不稳定
- 现象:相同查询有时1秒返回,有时超时
- 解决方案:
- 设置合理的超时时间(智谱API建议10-15秒)
- 实现指数退避重试机制
- 对耗时操作添加加载状态提示
问题2:内容审核拦截
- 现象:某些行业术语触发敏感词过滤
- 解决方案:
- 在提示词中明确分析的专业性
- 对输入内容进行预处理(替换敏感词同义词)
- 准备备用查询方案(如拆分问题)
7.2 提示工程优化心得
-
温度参数选择:
- 事实查询:temperature=0.3(更确定)
- 创意生成:temperature=0.7-1.0
- 商业分析推荐:temperature=0.5
-
结构化输出技巧:
python复制# 在提示词中强制指定格式
prompt += """请严格按以下顺序返回分析结果:
1. 第一段:核心结论(不超过3句话)
2. 第二段:关键数据(列表形式)
3. 第三段:行动建议(分条目列出)
不要包含任何解释性文字!"""
- 处理模型幻觉:
- 要求提供数据来源("请注明每个数据的参考来源")
- 设置置信度声明("对不确定的内容请明确标注'可能'")
- 交叉验证关键数据(对比多个搜索结果)
7.3 性能优化实战
场景:当分析报告需要包含多个维度时,响应时间过长
解决方案:
- 并行获取数据:
python复制async def gather_data(query):
search, examples, trends = await asyncio.gather(
search_tool.search(query),
db.get_industry_examples(query),
api.get_tech_trends()
)
return {"search": search, "examples": examples, "trends": trends}
- 流式输出优化:
python复制def stream_with_thoughts(prompt):
messages = [
{"role": "system", "content": "先思考再回答,展示推理过程"},
{"role": "user", "content": prompt}
]
full_response = ""
for chunk in llm.stream_chat(messages):
if "思考" in chunk: # 过滤内部推理过程
continue
full_response += chunk
yield chunk
logger.info(f"Completed response: {full_response[:200]}...")
- 缓存策略:
python复制from diskcache import Cache
cache = Cache("./analysis_cache")
@cache.memoize(expire=86400, tag="analysis")
def analyze_market(query):
# 昂贵计算过程
return heavy_analysis(query)
8. 项目扩展方向
8.1 多智能体协作系统
将单一顾问扩展为专家团队:
python复制class AgentTeam:
def __init__(self):
self.analyst = MarketAnalyst()
self.strategist = BusinessStrategist()
self.critic = RiskCritic()
def discuss(self, query):
# 分析师生成初稿
draft = self.analyst.analyze(query)
# 战略家补充建议
enhanced = self.strategist.review(draft)
# 风控官提出质疑
final = self.critic.challenge(enhanced)
return {
"analysis": draft,
"strategy": enhanced,
"risks": final
}
8.2 知识图谱集成
将分析结果结构化存储:
python复制def build_knowledge_graph(analysis):
entities = []
relations = []
# 提取市场实体
for competitor in analysis["competitors"]:
entities.append({
"type": "Company",
"name": competitor["name"],
"properties": {
"market_share": competitor["share"],
"strengths": competitor["advantage"]
}
})
# 构建关系
relations.append({
"source": analysis["query"],
"target": "SaaS Market",
"type": "belongs_to"
})
return {"entities": entities, "relations": relations}
8.3 自动化报告生成
python复制def generate_pdf_report(analysis):
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
doc = SimpleDocTemplate("report.pdf", pagesize=letter)
styles = getSampleStyleSheet()
story = []
# 添加标题
story.append(Paragraph(f"{analysis['query']}分析报告", styles["Title"]))
# 添加市场概况
story.append(Paragraph("1. 市场概况", styles["Heading2"]))
story.append(Paragraph(analysis["market_overview"], styles["Normal"]))
# 添加图表
draw_market_share_chart(analysis["competitors"])
story.append(Image("market_share.png"))
doc.build(story)
return "report.pdf"
这个项目的真正价值在于它提供了一个可扩展的框架,开发者可以基于此快速构建垂直领域的专业分析工具。我在实际项目中曾基于此架构开发过跨境电商选品分析、医疗市场准入评估等专业工具,核心架构保持稳定,只需替换领域特定的提示词和工具模块即可。
