前端转agent-【python】-18 Agent 与本地应用结合:让 AI 操作你的浏览器
前面的 Agent 只能活在终端里,今天让它“走出”命令行,直接操控你电脑上的浏览器——打开网页、填表单、点按钮、抓数据。
用 Playwright 当手,Ollama + Qwen3:4b 当脑,LangGraph 当神经,一步步做一个能帮你干活的自动化助手。
如果你写过前端 E2E 测试(Cypress / Playwright),这简直一模一样,只不过测试脚本现在由 AI 自动生成。
为什么 Agent 需要操作本地应用?
- 自动完成重复性工作:填报销单、批量截图、数据采集
- 打通线上信息与本地操作:查完天气自动生成 Excel 报表
- 让 Agent 成为真正的“数字员工”
Vue 3 类比:前端用 Playwright 写 E2E 测试,是“脚本模拟用户操作”;Agent 做同样的事,只是脚本由 LLM 实时生成,并根据结果动态调整。
环境准备
pip install ollama langgraph playwright
playwright install chromium # 安装浏览器内核
模型:
ollama pull qwen3:4b
第一步:给 Agent 一双“手”——浏览器工具
先把 Playwright 的常用操作封装成工具函数,供 LLM 调用。
# browser_tools.py
from playwright.sync_api import sync_playwright
import base64
from typing import Optional
# 全局 Playwright 实例(简单起见)
_playwright = None
_browser = None
_page = None
def start_browser():
global _playwright, _browser, _page
_playwright = sync_playwright().start()
_browser = _playwright.chromium.launch(headless=False) # 显示浏览器方便观察
_page = _browser.new_page()
return "浏览器已启动"
def goto_url(url: str) -> str:
_page.goto(url)
return f"已打开 {_page.title()}"
def fill_input(selector: str, text: str) -> str:
_page.fill(selector, text)
return f"已在 {selector} 输入: {text}"
def click_button(selector: str) -> str:
_page.click(selector)
return f"已点击 {selector}"
def get_page_text() -> str:
return _page.inner_text("body")[:2000] # 返回前2000字符,避免超长
def take_screenshot() -> str:
"""截图并返回 base64(可传给视觉模型分析)"""
b64 = base64.b64encode(_page.screenshot()).decode("utf-8")
return b64
def close_browser():
global _playwright
_browser.close()
_playwright.stop()
return "浏览器已关闭"
第二步:用 LangGraph 搭建“浏览器操作 Agent”
LLM 根据用户指令,生成一系列浏览器操作(类似 Function Calling),Agent 依次执行并反馈结果。
# browser_agent.py
import json, ollama
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, END
from browser_tools import (
start_browser, goto_url, fill_input, click_button,
get_page_text, take_screenshot, close_browser
)
MODEL = "qwen3:4b"
# 工具描述(喂给 LLM)
TOOLS_DESC = """
可用工具:
1. goto_url(url) - 打开网页
2. fill_input(selector, text) - 在输入框填入内容
3. click_button(selector) - 点击按钮
4. get_page_text() - 获取当前页面文本
5. take_screenshot() - 截图(返回base64)
6. close_browser() - 关闭浏览器
当你需要操作浏览器时,输出JSON格式的步骤列表:
{"steps": [{"tool": "工具名", "args": {...}}, ...]}
如果用户问题不需要浏览器,直接回答。
"""
class BrowserState(TypedDict):
user_input: str
steps: list[dict] # 待执行的浏览器操作步骤
current_step: int
final_answer: str
def plan_steps(state: BrowserState) -> dict:
"""LLM 生成操作计划"""
prompt = f"""{TOOLS_DESC}
用户需求:{state['user_input']}
请决定是否需要浏览器操作。需要则输出JSON:{{"steps": [...]}};不需要则直接回答。"""
res = ollama.generate(model=MODEL, prompt=prompt)
text = res["response"].strip()
try:
plan = json.loads(text)
if "steps" in plan:
return {"steps": plan["steps"], "current_step": 0}
except:
pass
return {"final_answer": text}
def execute_step(state: BrowserState) -> dict:
"""执行当前步骤"""
steps = state["steps"]
idx = state["current_step"]
if idx >= len(steps):
return {}
step = steps[idx]
tool_name = step["tool"]
args = step.get("args", {})
# 根据工具名调用对应函数(安全起见,生产环境需要严格校验)
if tool_name == "goto_url":
result = goto_url(**args)
elif tool_name == "fill_input":
result = fill_input(**args)
elif tool_name == "click_button":
result = click_button(**args)
elif tool_name == "get_page_text":
result = get_page_text()
elif tool_name == "take_screenshot":
result = "截图已生成(base64省略)" # 实际可保存或分析
take_screenshot()
elif tool_name == "close_browser":
result = close_browser()
else:
result = f"未知工具:{tool_name}"
# 把执行结果追加到步骤信息中
steps[idx]["result"] = result
return {"steps": steps, "current_step": idx + 1}
def check_done(state: BrowserState) -> Literal["execute", "summarize"]:
if state["current_step"] < len(state["steps"]):
return "execute"
return "summarize"
def summarize(state: BrowserState) -> dict:
"""所有步骤执行完后,让LLM根据结果生成最终回复"""
report = "\n".join(
f"步骤{i+1}: {s['tool']} -> {s.get('result','')}"
for i, s in enumerate(state["steps"])
)
prompt = f"""用户需求:{state['user_input']}
操作记录:{report}
请用自然语言总结操作结果。"""
res = ollama.generate(model=MODEL, prompt=prompt)
return {"final_answer": res["response"].strip()}
# 构建图
builder = StateGraph(BrowserState)
builder.add_node("plan", plan_steps)
builder.add_node("execute", execute_step)
builder.add_node("summarize", summarize)
builder.set_entry_point("plan")
builder.add_conditional_edges("plan", lambda s: "execute" if s.get("steps") else "end", {
"execute": "execute",
"end": END
})
builder.add_conditional_edges("execute", check_done, {
"execute": "execute",
"summarize": "summarize"
})
builder.add_edge("summarize", END)
agent = builder.compile()
# 运行前先启动浏览器
start_browser()
if __name__ == "__main__":
while True:
user = input("\n🧑 你: ")
if user == "/bye":
close_browser()
break
state = {"user_input": user, "steps": [], "current_step": 0, "final_answer": ""}
result = agent.invoke(state)
print(f"🤖 Agent: {result.get('final_answer')}")
运行效果:
🧑 你: 打开百度,搜索“Python教程”,然后告诉我第一个结果的标题
(浏览器自动打开百度,输入搜索词,点击搜索,截图,获取文本)
🤖 Agent: 百度已打开,搜索"Python教程"后,第一个结果是"Python基础教程 | 菜鸟教程"
整个过程无需手动操作,Agent 自动规划步骤并执行。
Vue 3 对比:从 E2E 测试到 AI 测试
前端工程师写 Playwright 测试通常是预先定义好步骤:
// e2e.spec.ts
test('搜索 Python 教程', async ({ page }) => {
await page.goto('https://baidu.com');
await page.fill('#kw', 'Python教程');
await page.click('#su');
await expect(page.locator('.result')).toContainText('菜鸟教程');
});
AI Agent 把“写死步骤”变成“根据自然语言生成步骤并执行”,本质上是动态生成测试脚本。
你的 Vue 组件经验帮你理解:页面上的元素就是 selector,表单交互就是 fill + click,Agent 只是把用户的话翻译成这些操作。
安全与最佳实践
- 沙盒环境:务必在虚拟机或隔离环境中运行,避免误删文件或泄露隐私。
- 审批机制:结合第 16 篇的人机协同,对危险操作(close_browser、修改文件)加入
interrupt。 - 操作日志:每一步都记录
result,方便回溯。 - 视觉反馈:用截图 + 视觉模型实现“页面理解”,比如“找到‘登录’按钮并点击”而不是硬编码
selector,这需要再接入视觉模型(如 llama3.2-vision)分析截图给出坐标。
拓展思路
- 表格填写自动化:读取 Excel → 逐条填入 Web 表单
- 价格监控:每天定时抓取电商价格,存入 CSV
- 一键部署脚本:Agent 操作 VPS 管理面板,完成网站部署
- 前端 Bug 复现:描述 bug,Agent 自动打开页面复现并截图
这些能力结合你的前端背景,可以做出非常惊艳的内部工具。
总结
- 用 Playwright 给 Agent 装上“手”,让它能像人一样操作浏览器。
- LangGraph 负责将用户指令翻译成操作步骤并逐条执行,形成“规划-执行-总结”闭环。
- 对前端开发者来说,这套思路就是 E2E 测试的 AI 增强版,而且可以和 Vue 组件无缝集成(比如在管理后台嵌入一个“语音助手”直接操控后台页面)。
- 安全第一,务必在可控环境中测试。
现在,试着让你的 Agent 帮你打开公司后台,自动导出今天的报表吧!
python browser_agent.py