茂道 commited on
Commit
6b5fe86
·
1 Parent(s): 38c8b88
.idea/.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
.idea/inspectionProfiles/Project_Default.xml ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
+ <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
6
+ <option name="ignoredPackages">
7
+ <value>
8
+ <list size="126">
9
+ <item index="0" class="java.lang.String" itemvalue="DBUtils" />
10
+ <item index="1" class="java.lang.String" itemvalue="Flask-MySQL" />
11
+ <item index="2" class="java.lang.String" itemvalue="requests" />
12
+ <item index="3" class="java.lang.String" itemvalue="gunicorn" />
13
+ <item index="4" class="java.lang.String" itemvalue="Flask" />
14
+ <item index="5" class="java.lang.String" itemvalue="Werkzeug" />
15
+ <item index="6" class="java.lang.String" itemvalue="pillow" />
16
+ <item index="7" class="java.lang.String" itemvalue="PyMySQL" />
17
+ <item index="8" class="java.lang.String" itemvalue="jinja2" />
18
+ <item index="9" class="java.lang.String" itemvalue="pandas" />
19
+ <item index="10" class="java.lang.String" itemvalue="scipy" />
20
+ <item index="11" class="java.lang.String" itemvalue="maplpy" />
21
+ <item index="12" class="java.lang.String" itemvalue="dataclasses" />
22
+ <item index="13" class="java.lang.String" itemvalue="hsfpy3" />
23
+ <item index="14" class="java.lang.String" itemvalue="util" />
24
+ <item index="15" class="java.lang.String" itemvalue="typing_extensions" />
25
+ <item index="16" class="java.lang.String" itemvalue="index" />
26
+ <item index="17" class="java.lang.String" itemvalue="numpy" />
27
+ <item index="18" class="java.lang.String" itemvalue="browsergym" />
28
+ <item index="19" class="java.lang.String" itemvalue="browser-use" />
29
+ <item index="20" class="java.lang.String" itemvalue="gradio" />
30
+ <item index="21" class="java.lang.String" itemvalue="chunkr-ai" />
31
+ <item index="22" class="java.lang.String" itemvalue="docx2markdown" />
32
+ <item index="23" class="java.lang.String" itemvalue="camel-ai" />
33
+ <item index="24" class="java.lang.String" itemvalue="pytest-qt" />
34
+ <item index="25" class="java.lang.String" itemvalue="shapely" />
35
+ <item index="26" class="java.lang.String" itemvalue="numba" />
36
+ <item index="27" class="java.lang.String" itemvalue="absl-py" />
37
+ <item index="28" class="java.lang.String" itemvalue="gensim" />
38
+ <item index="29" class="java.lang.String" itemvalue="bs4" />
39
+ <item index="30" class="java.lang.String" itemvalue="cvxpy" />
40
+ <item index="31" class="java.lang.String" itemvalue="scikit-learn" />
41
+ <item index="32" class="java.lang.String" itemvalue="pyscf" />
42
+ <item index="33" class="java.lang.String" itemvalue="nameko" />
43
+ <item index="34" class="java.lang.String" itemvalue="pandasql" />
44
+ <item index="35" class="java.lang.String" itemvalue="rdkit" />
45
+ <item index="36" class="java.lang.String" itemvalue="PyQt5" />
46
+ <item index="37" class="java.lang.String" itemvalue="pycryptodomex" />
47
+ <item index="38" class="java.lang.String" itemvalue="kneed" />
48
+ <item index="39" class="java.lang.String" itemvalue="PyPDF2" />
49
+ <item index="40" class="java.lang.String" itemvalue="tree-sitter-languages" />
50
+ <item index="41" class="java.lang.String" itemvalue="uvloop" />
51
+ <item index="42" class="java.lang.String" itemvalue="xlrd" />
52
+ <item index="43" class="java.lang.String" itemvalue="Flask-Caching" />
53
+ <item index="44" class="java.lang.String" itemvalue="GitPython" />
54
+ <item index="45" class="java.lang.String" itemvalue="ruptures" />
55
+ <item index="46" class="java.lang.String" itemvalue="jupyter_client" />
56
+ <item index="47" class="java.lang.String" itemvalue="graphql-core" />
57
+ <item index="48" class="java.lang.String" itemvalue="Flask-WTF" />
58
+ <item index="49" class="java.lang.String" itemvalue="yolk" />
59
+ <item index="50" class="java.lang.String" itemvalue="Flask-SQLAlchemy" />
60
+ <item index="51" class="java.lang.String" itemvalue="APScheduler" />
61
+ <item index="52" class="java.lang.String" itemvalue="psutil" />
62
+ <item index="53" class="java.lang.String" itemvalue="torchinfo" />
63
+ <item index="54" class="java.lang.String" itemvalue="xarray" />
64
+ <item index="55" class="java.lang.String" itemvalue="pika" />
65
+ <item index="56" class="java.lang.String" itemvalue="mongomock" />
66
+ <item index="57" class="java.lang.String" itemvalue="lightgbm" />
67
+ <item index="58" class="java.lang.String" itemvalue="jsonlines" />
68
+ <item index="59" class="java.lang.String" itemvalue="torchsummary" />
69
+ <item index="60" class="java.lang.String" itemvalue="PyJWT" />
70
+ <item index="61" class="java.lang.String" itemvalue="gql" />
71
+ <item index="62" class="java.lang.String" itemvalue="folium" />
72
+ <item index="63" class="java.lang.String" itemvalue="fastdtw" />
73
+ <item index="64" class="java.lang.String" itemvalue="Flask-GraphQL" />
74
+ <item index="65" class="java.lang.String" itemvalue="antlr4-python3-runtime" />
75
+ <item index="66" class="java.lang.String" itemvalue="tree-sitter" />
76
+ <item index="67" class="java.lang.String" itemvalue="graphene" />
77
+ <item index="68" class="java.lang.String" itemvalue="docker" />
78
+ <item index="69" class="java.lang.String" itemvalue="catboost" />
79
+ <item index="70" class="java.lang.String" itemvalue="tensorflow" />
80
+ <item index="71" class="java.lang.String" itemvalue="XlsxWriter" />
81
+ <item index="72" class="java.lang.String" itemvalue="jupyter" />
82
+ <item index="73" class="java.lang.String" itemvalue="seaborn" />
83
+ <item index="74" class="java.lang.String" itemvalue="pytest-mock" />
84
+ <item index="75" class="java.lang.String" itemvalue="pytest-cov" />
85
+ <item index="76" class="java.lang.String" itemvalue="Flask-Limiter" />
86
+ <item index="77" class="java.lang.String" itemvalue="xgboost" />
87
+ <item index="78" class="java.lang.String" itemvalue="coverage" />
88
+ <item index="79" class="java.lang.String" itemvalue="PyMuPDF" />
89
+ <item index="80" class="java.lang.String" itemvalue="python-docx" />
90
+ <item index="81" class="java.lang.String" itemvalue="pyzbar" />
91
+ <item index="82" class="java.lang.String" itemvalue="pymongo" />
92
+ <item index="83" class="java.lang.String" itemvalue="opencv-python" />
93
+ <item index="84" class="java.lang.String" itemvalue="pytest" />
94
+ <item index="85" class="java.lang.String" itemvalue="faiss-cpu" />
95
+ <item index="86" class="java.lang.String" itemvalue="datasketch" />
96
+ <item index="87" class="java.lang.String" itemvalue="kaleido" />
97
+ <item index="88" class="java.lang.String" itemvalue="xlwt" />
98
+ <item index="89" class="java.lang.String" itemvalue="astor" />
99
+ <item index="90" class="java.lang.String" itemvalue="plotly" />
100
+ <item index="91" class="java.lang.String" itemvalue="toml" />
101
+ <item index="92" class="java.lang.String" itemvalue="WTForms" />
102
+ <item index="93" class="java.lang.String" itemvalue="statsmodels" />
103
+ <item index="94" class="java.lang.String" itemvalue="pyberny" />
104
+ <item index="95" class="java.lang.String" itemvalue="arch" />
105
+ <item index="96" class="java.lang.String" itemvalue="Flask-Testing" />
106
+ <item index="97" class="java.lang.String" itemvalue="gmpy2" />
107
+ <item index="98" class="java.lang.String" itemvalue="pulp" />
108
+ <item index="99" class="java.lang.String" itemvalue="Flask-RESTful" />
109
+ <item index="100" class="java.lang.String" itemvalue="pmdarima" />
110
+ <item index="101" class="java.lang.String" itemvalue="textblob" />
111
+ <item index="102" class="java.lang.String" itemvalue="openpyxl" />
112
+ <item index="103" class="java.lang.String" itemvalue="playwright" />
113
+ <item index="104" class="java.lang.String" itemvalue="openai" />
114
+ <item index="105" class="java.lang.String" itemvalue="markdown2" />
115
+ <item index="106" class="java.lang.String" itemvalue="contextvars" />
116
+ <item index="107" class="java.lang.String" itemvalue="langchain" />
117
+ <item index="108" class="java.lang.String" itemvalue="jsonpath" />
118
+ <item index="109" class="java.lang.String" itemvalue="FastAPI" />
119
+ <item index="110" class="java.lang.String" itemvalue="uvicorn" />
120
+ <item index="111" class="java.lang.String" itemvalue="retry" />
121
+ <item index="112" class="java.lang.String" itemvalue="json-repair" />
122
+ <item index="113" class="java.lang.String" itemvalue="langchain-core" />
123
+ <item index="114" class="java.lang.String" itemvalue="jmespath" />
124
+ <item index="115" class="java.lang.String" itemvalue="opentelemetry-proto" />
125
+ <item index="116" class="java.lang.String" itemvalue="opentelemetry-exporter-otlp-proto-grpc" />
126
+ <item index="117" class="java.lang.String" itemvalue="opentelemetry-api" />
127
+ <item index="118" class="java.lang.String" itemvalue="opentelemetry-sdk" />
128
+ <item index="119" class="java.lang.String" itemvalue="grpcio" />
129
+ <item index="120" class="java.lang.String" itemvalue="mcp" />
130
+ <item index="121" class="java.lang.String" itemvalue="opentelemetry-exporter-otlp-proto-common" />
131
+ <item index="122" class="java.lang.String" itemvalue="opentelemetry-exporter-otlp-proto-http" />
132
+ <item index="123" class="java.lang.String" itemvalue="redis" />
133
+ <item index="124" class="java.lang.String" itemvalue="opentelemetry-semantic-conventions" />
134
+ <item index="125" class="java.lang.String" itemvalue="rocketmq-python-client" />
135
+ </list>
136
+ </value>
137
+ </option>
138
+ </inspection_tool>
139
+ <inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
140
+ <option name="ignoredErrors">
141
+ <list>
142
+ <option value="E302" />
143
+ </list>
144
+ </option>
145
+ </inspection_tool>
146
+ <inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
147
+ <option name="ignoredErrors">
148
+ <list>
149
+ <option value="N803" />
150
+ <option value="N801" />
151
+ <option value="N806" />
152
+ </list>
153
+ </option>
154
+ </inspection_tool>
155
+ <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
156
+ <option name="ignoredIdentifiers">
157
+ <list>
158
+ <option value="dict.has_key" />
159
+ <option value="fastchat.modules" />
160
+ <option value="dict.query" />
161
+ <option value="nest_asyncio" />
162
+ <option value="aiohttp.client_reqrep.ClientResponse.__await__" />
163
+ </list>
164
+ </option>
165
+ </inspection_tool>
166
+ </profile>
167
+ </component>
.idea/inspectionProfiles/profiles_settings.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
.idea/misc.xml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
4
+ </project>
.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/werewolf_1.iml" filepath="$PROJECT_DIR$/.idea/werewolf_1.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
.idea/werewolf_1.iml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$" />
5
+ <orderEntry type="inheritedJdk" />
6
+ <orderEntry type="sourceFolder" forTests="false" />
7
+ </component>
8
+ </module>
Dockerfile CHANGED
@@ -11,4 +11,4 @@ RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
  RUN pip3 install werewolf-agent-build-sdk==0.0.1
12
  COPY --chown=user . /app
13
 
14
- CMD ["python3", "app.py"]
 
11
  RUN pip3 install werewolf-agent-build-sdk==0.0.1
12
  COPY --chown=user . /app
13
 
14
+ CMD ["python3", "werewolf/app.py"]
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ fastapi
2
+ uvicorn[standard]
3
+ openai
werewolf/app.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ from agent_build_sdk.builder import AgentBuilder
4
+ from agent_build_sdk.example.werewolf.hunter.hunter_agent import HunterAgent
5
+ from agent_build_sdk.example.werewolf.seer.seer_agent import SeerAgent
6
+ from agent_build_sdk.example.werewolf.villager.villager_agent import VillagerAgent
7
+ from agent_build_sdk.example.werewolf.witch.witch_agent import WitchAgent
8
+ from agent_build_sdk.example.werewolf.wolf.wolf_agent import WolfAgent
9
+ from agent_build_sdk.model.roles import ROLE_VILLAGER,ROLE_WOLF,ROLE_SEER,ROLE_WITCH,ROLE_HUNTER
10
+ from agent_build_sdk.sdk.werewolf_agent import WerewolfAgent
11
+
12
+ if __name__ == '__main__':
13
+ name = 'spy'
14
+ agent = WerewolfAgent(name, model_name=os.getenv('MODEL_NAME'))
15
+ agent.register_role_agent(ROLE_VILLAGER, VillagerAgent())
16
+ agent.register_role_agent(ROLE_WOLF, WolfAgent())
17
+ agent.register_role_agent(ROLE_SEER, SeerAgent())
18
+ agent.register_role_agent(ROLE_WITCH, WitchAgent())
19
+ agent.register_role_agent(ROLE_HUNTER, HunterAgent())
20
+ agent_builder = AgentBuilder(name, agent=agent)
21
+ agent_builder.start()
werewolf/hunter/hunter_agent.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent_build_sdk.model.roles import ROLE_HUNTER
2
+ from agent_build_sdk.model.werewolf_model import AgentResp, AgentReq, STATUS_START, STATUS_WOLF_SPEECH, \
3
+ STATUS_VOTE_RESULT, STATUS_SKILL, STATUS_SKILL_RESULT, STATUS_NIGHT_INFO, STATUS_DAY, STATUS_DISCUSS, STATUS_VOTE, \
4
+ STATUS_RESULT, STATUS_NIGHT
5
+ from agent_build_sdk.utils.logger import logger
6
+ from agent_build_sdk.sdk.role_agent import BasicRoleAgent
7
+ from agent_build_sdk.sdk.agent import format_prompt
8
+ from agent_build_sdk.example.werewolf.hunter.prompt import DESC_PROMPT, VOTE_PROMPT, SKILL_PROMPT
9
+
10
+
11
+ class HunterAgent(BasicRoleAgent):
12
+ """猎人角色Agent"""
13
+
14
+ def __init__(self, llm_caller=None, memory=None):
15
+ super().__init__(ROLE_HUNTER, llm_caller, memory)
16
+
17
+ def perceive(self, req=AgentReq):
18
+ if req.status == STATUS_START:
19
+ self.memory.clear()
20
+ self.memory.set_variable("name", req.name)
21
+ self.memory.append_history("主持人:大家好,我们正在玩狼人杀游戏,6人局,包括预言家、女巫、猎人、平民和狼人")
22
+ self.memory.append_history("主持人:你好,你分配到的角色是[猎人]")
23
+ if req.status == STATUS_NIGHT:
24
+ self.memory.append_history("主持人:现在进入夜晚,天黑请闭眼")
25
+ if req.status == STATUS_NIGHT_INFO:
26
+ self.memory.append_history(f"主持人:天亮了!昨天晚上的信息是: {req.message}")
27
+ elif req.status == STATUS_DISCUSS: # 发言环节
28
+ if req.name:
29
+ # 其他玩家发言
30
+ self.memory.append_history(req.name + ': ' + req.message)
31
+ else:
32
+ # 主持人发言
33
+ self.memory.append_history('主持人: 现在进入第{}天。'.format(str(req.round)))
34
+ self.memory.append_history('主持人: 每个玩家描述自己的信息。')
35
+ elif req.status == STATUS_VOTE: # 投票环节
36
+ self.memory.append_history(req.name + ': ' + req.message)
37
+ elif req.status == STATUS_VOTE_RESULT: # 投票结果
38
+ out_player = req.name if req.name else req.message
39
+ if out_player:
40
+ self.memory.append_history('主持人: 投票结果是:{}。'.format(out_player))
41
+ # 如果猎人被投票出局,触发技能
42
+ if out_player == self.memory.load_variable("name"):
43
+ self.memory.append_history('主持人: 猎人被投票出局,可以发动技能带走一名玩家。')
44
+ else:
45
+ self.memory.append_history('主持人: 无人出局。')
46
+ elif req.status == STATUS_SKILL_RESULT: # 猎人技能
47
+ self.memory.append_history(f'主持人: 猎人,你带走了{req.message}')
48
+ elif req.status == STATUS_RESULT:
49
+ self.memory.append_history(req.message)
50
+ else:
51
+ raise NotImplementedError
52
+
53
+ def interact(self, req=AgentReq) -> AgentResp:
54
+ logger.info("hunter interact: {}".format(req))
55
+ if req.status == STATUS_DISCUSS:
56
+ prompt = format_prompt(DESC_PROMPT,
57
+ {"name": self.memory.load_variable("name"),
58
+ "history": "\n".join(self.memory.load_history())
59
+ })
60
+ logger.info("prompt:" + prompt)
61
+ result = self.llm_caller(prompt)
62
+ logger.info("hunter interact result: {}".format(result))
63
+ return AgentResp(success=True, result=result, errMsg=None)
64
+
65
+ elif req.status == STATUS_VOTE:
66
+ self.memory.append_history('主持人: 到了投票的时候了。每个人,请指向你认为可能是狼人的人。')
67
+ choices = [name for name in req.message.split(",") if name != self.memory.load_variable("name")] # 排除自己
68
+ self.memory.set_variable("choices", choices)
69
+ prompt = format_prompt(VOTE_PROMPT, {"name": self.memory.load_variable("name"),
70
+ "choices": choices,
71
+ "history": "\n".join(self.memory.load_history())
72
+ })
73
+ logger.info("prompt:" + prompt)
74
+ result = self.llm_caller(prompt)
75
+ logger.info("hunter interact result: {}".format(result))
76
+ return AgentResp(success=True, result=result, errMsg=None)
77
+
78
+ elif req.status == STATUS_SKILL:
79
+ self.memory.append_history('主持人: 猎人,请选择你要带走的玩家。')
80
+ choices = [name for name in req.message.split(",") if name != self.memory.load_variable("name")] # 排除自己
81
+ self.memory.set_variable("choices", choices)
82
+ prompt = format_prompt(SKILL_PROMPT, {"name": self.memory.load_variable("name"),
83
+ "choices": choices,
84
+ "history": "\n".join(self.memory.load_history())
85
+ })
86
+ logger.info("prompt:" + prompt)
87
+ result = self.llm_caller(prompt)
88
+ logger.info("hunter skill result: {}".format(result))
89
+ return AgentResp(success=True, result=result, skill_target_player=result, errMsg=None)
90
+ else:
91
+ raise NotImplementedError
werewolf/hunter/prompt.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DESC_PROMPT = """{history}
2
+ 你是{name},你是一名猎人。你的目标是找出狼人,保护村庄。你拥有特殊技能:当你被投票出局或被狼人杀死时,可以开枪带走一名玩家。
3
+ 请根据游戏规则和此前的对话,提供一个自然且合理的描述,确保:
4
+
5
+ 你的描述要真实可信,表现出对村庄的关心和对狼人的警惕。
6
+ 你的发言应当像一个猎人,使用日常的语言表达方式,但可以暗示你有能力在死亡时带走一个人。
7
+ 你可以描述你观察到的可疑行为,或分享你对其他玩家的看法。
8
+ 要谨慎发言,避免过早暴露自己的身份,但也可以适当威慑狼人。
9
+ 以下是几个合适的示例:
10
+ "我昨晚听到东边有些动静,我已经做好了准备。"
11
+ "我觉得4号玩家的行为有点反常,如果我被淘汰,我会记住这一点。"
12
+ "我一直在观察每个人,如果我被杀,我会带走我认为最可疑的人。"
13
+ 请按照类似的风格,结合当前游戏局势进行发言:
14
+ """
15
+
16
+ VOTE_PROMPT = """{history}
17
+ 你是{name},作为一名猎人,你的使命是找出潜伏的狼人。
18
+ 请仔细分析当前游戏局势,选择你认为最可能是狼人的玩家进行投票:
19
+
20
+ 注意观察每个玩家的发言,寻找逻辑矛盾或可疑之处。
21
+ 关注玩家之间的互动,是否有人在刻意包庇或陷害他人。
22
+ 分析投票倾向,是否有玩家在关键时刻改变立场。
23
+ 留意反常行为,如过分激动或过于沉默的玩家。
24
+ 从以下玩家中选择你认为最可能是狼人的人:{choices}
25
+ 请直接返回你要投票的玩家名字:
26
+ """
27
+
28
+ SKILL_PROMPT = """{history}
29
+ 你是{name},作为猎人,你被淘汰了,现在可以使用你的技能带走一名玩家。
30
+ 请仔细分析当前游戏局势,选择你认为最可能是狼人的玩家:
31
+
32
+ 回顾所有玩家的发言和行为,找出最可疑的人。
33
+ 考虑谁最有可能是狼人,带走他对村民阵营最有利。
34
+ 如果你不确定谁是狼人,可以考虑带走最有影响力的玩家。
35
+ 从以下玩家中选择你要带走的人:{choices}
36
+ 请直接返回你要带走的玩家名字:
37
+ """
werewolf/seer/prompt.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DESC_PROMPT = """{history}
2
+ 你是{name},你是一名预言家。你的目标是找出狼人,保护村庄。你每晚可以查验一名玩家的身份。
3
+ 你已经查验过的玩家及其身份:{checked_players}
4
+
5
+ 请根据游戏规则和此前的对话,提供一个自然且合理的描述,确保:
6
+
7
+ 你的描述要真实可信,表现出对村庄的关心和对狼人的警惕。
8
+ 你可以选择是否公开自己的预言家身份,这取决于游戏局势。
9
+ 如果你选择公开身份,可以分享你的查验结果,但要注意这可能会使你成为狼人的目标。
10
+ 如果你选择隐藏身份,可以用暗示的方式引导村民投票。
11
+ 以下是几个合适的示例:
12
+ "我有重要的信息要分享,我是预言家,我查验了3号玩家,他是好人。"
13
+ "根据我的观察,2号玩家的行为很可疑,我建议大家关注他。"
14
+ "我相信我们之中有人知道真相,希望能够站出来指引我们。"
15
+ 请按照类似的风格,结合当前游戏局势进行发言:
16
+ """
17
+
18
+ VOTE_PROMPT = """{history}
19
+ 你是{name},作为预言家,你的使命是找出潜伏的狼人。
20
+ 你已经查验过的玩家及其身份:{checked_players}
21
+
22
+ 请仔细分析当前游戏局势,选择你认为最可能是狼人的玩家进行投票:
23
+
24
+ 优先考虑你查验出的狼人。
25
+ 注意观察每个玩家的发言,寻找逻辑矛盾或可疑之处。
26
+ 关注玩家之间的互动,是否有人在刻意包庇或陷害他人。
27
+ 分析投票倾向,是否有玩家在关键时刻改变立场。
28
+ 从以下玩家中选择你认为最可能是狼人的人:{choices}
29
+ 请直接返回你要投票的玩家名字:
30
+ """
31
+
32
+ SKILL_PROMPT = """{history}
33
+ 你是{name},作为预言家,现在是你使用技能的时间。
34
+ 你已经查验过的玩家及其身份:{checked_players}
35
+
36
+ 请仔细分析当前游戏局势,选择一个最佳的查验目标:
37
+
38
+ 1. 优先查验你最怀疑的玩家
39
+ 2. 考虑查验那些发言可疑或行为反常的玩家
40
+ 3. 如果有玩家声称自己是特殊身份,可以考虑查验他
41
+ 4. 避免查验那些你认为很可能是好人的玩家
42
+
43
+ 从以下玩家中选择你要查验的人:{choices}
44
+ 请直接返回你要查验的玩家名字:
45
+ """
werewolf/seer/seer_agent.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent_build_sdk.model.roles import ROLE_SEER
2
+ from agent_build_sdk.model.werewolf_model import AgentResp, AgentReq, STATUS_START, STATUS_WOLF_SPEECH, \
3
+ STATUS_VOTE_RESULT, STATUS_SKILL, STATUS_SKILL_RESULT, STATUS_NIGHT_INFO, STATUS_DAY, STATUS_DISCUSS, STATUS_VOTE, \
4
+ STATUS_RESULT, STATUS_NIGHT, STATUS_SKILL
5
+ from agent_build_sdk.utils.logger import logger
6
+ from agent_build_sdk.sdk.role_agent import BasicRoleAgent
7
+ from agent_build_sdk.sdk.agent import format_prompt
8
+ from agent_build_sdk.example.werewolf.seer.prompt import DESC_PROMPT, VOTE_PROMPT, SKILL_PROMPT
9
+
10
+
11
+ class SeerAgent(BasicRoleAgent):
12
+ """预言家角色Agent"""
13
+
14
+ def __init__(self, llm_caller=None, memory=None):
15
+ super().__init__(ROLE_SEER, llm_caller, memory)
16
+ self.memory.set_variable("checked_players", {}) # 存储已查验的玩家信息
17
+
18
+ def perceive(self, req=AgentReq):
19
+ if req.status == STATUS_START:
20
+ self.memory.clear()
21
+ self.memory.set_variable("name", req.name)
22
+ self.memory.set_variable("checked_players", {}) # 重置已查验的玩家信息
23
+ self.memory.append_history("主持人:大家好,我们正在玩狼人杀游戏,6人局,包括预言家、女巫、猎人、平民和狼人")
24
+ self.memory.append_history("主持人:你好,你分配到的角色是[预言家]")
25
+ if req.status == STATUS_NIGHT:
26
+ self.memory.append_history("主持人:现在进入夜晚,天黑请闭眼")
27
+ if req.status == STATUS_SKILL_RESULT:
28
+ # 记录查验结果
29
+ self.memory.append_history(f"主持人:{req.name}的身份是{req.message}")
30
+ checked_players = self.memory.load_variable("checked_players")
31
+ checked_players[req.name] = req.message
32
+ self.memory.set_variable("checked_players", checked_players)
33
+ if req.status == STATUS_NIGHT_INFO:
34
+ self.memory.append_history(f"主持人:天亮了!昨天晚上的信息是: {req.message}")
35
+ elif req.status == STATUS_DISCUSS: # 发言环节
36
+ if req.name:
37
+ # 其他玩家发言
38
+ self.memory.append_history(req.name + ': ' + req.message)
39
+ else:
40
+ # 主持人发言
41
+ self.memory.append_history('主持人: 现在进入第{}天。'.format(str(req.round)))
42
+ self.memory.append_history('主持人: 每个玩家描述自己的信息。')
43
+ elif req.status == STATUS_VOTE: # 投票环节
44
+ self.memory.append_history(req.name + ': ' + req.message)
45
+ elif req.status == STATUS_VOTE_RESULT: # 投票环节
46
+ out_player = req.name if req.name else req.message
47
+ if out_player:
48
+ self.memory.append_history('主持人: 投票结果是:{}。'.format(out_player))
49
+ else:
50
+ self.memory.append_history('主持人: 无人出局。')
51
+ elif req.status == STATUS_RESULT:
52
+ self.memory.append_history(req.message)
53
+ else:
54
+ raise NotImplementedError
55
+
56
+ def interact(self, req=AgentReq) -> AgentResp:
57
+ logger.info("seer interact: {}".format(req))
58
+ if req.status == STATUS_DISCUSS:
59
+ checked_players = self.memory.load_variable("checked_players")
60
+ prompt = format_prompt(DESC_PROMPT,
61
+ {"name": self.memory.load_variable("name"),
62
+ "checked_players": checked_players,
63
+ "history": "\n".join(self.memory.load_history())
64
+ })
65
+ logger.info("prompt:" + prompt)
66
+ result = self.llm_caller(prompt)
67
+ logger.info("seer interact result: {}".format(result))
68
+ return AgentResp(success=True, result=result, errMsg=None)
69
+
70
+ elif req.status == STATUS_VOTE:
71
+ self.memory.append_history('主持人: 到了投票的时候了。每个人,请指向你认为可能是狼人的人。')
72
+ checked_players = self.memory.load_variable("checked_players")
73
+ choices = [name for name in req.message.split(",") if name != self.memory.load_variable("name")] # 排除自己
74
+ self.memory.set_variable("choices", choices)
75
+ prompt = format_prompt(VOTE_PROMPT, {"name": self.memory.load_variable("name"),
76
+ "checked_players": checked_players,
77
+ "choices": choices,
78
+ "history": "\n".join(self.memory.load_history())
79
+ })
80
+ logger.info("prompt:" + prompt)
81
+ result = self.llm_caller(prompt)
82
+ logger.info("seer interact result: {}".format(result))
83
+ return AgentResp(success=True, result=result, errMsg=None)
84
+
85
+ elif req.status == STATUS_SKILL:
86
+ checked_players = self.memory.load_variable("checked_players")
87
+ choices = [name for name in req.message.split(",")
88
+ if name != self.memory.load_variable("name") and name not in checked_players] # 排除自己和已查验的
89
+ self.memory.set_variable("choices", choices)
90
+ prompt = format_prompt(SKILL_PROMPT, {
91
+ "name": self.memory.load_variable("name"),
92
+ "checked_players": checked_players,
93
+ "choices": choices,
94
+ "history": "\n".join(self.memory.load_history())
95
+ })
96
+ logger.info("prompt:" + prompt)
97
+ result = self.llm_caller(prompt)
98
+ logger.info("seer skill result: {}".format(result))
99
+ return AgentResp(success=True, result=result, errMsg=None)
100
+ else:
101
+ raise NotImplementedError
werewolf/villager/prompt.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DESC_PROMPT = """{history}
2
+ 你是{name},你是一名平民。你的目标是找出狼人,保护村庄。
3
+ 请根据游戏规则和此前的对话,提供一个自然且合理的描述,确保:
4
+
5
+ 你的描述要真实可信,表现出对村庄的关心和对狼人的警惕。
6
+ 你的发言应当像一个普通村民,使用日常的语言表达方式。
7
+ 你可以描述你观察到的可疑行为,或分享你对其他玩家的看法。
8
+ 要谨慎发言,避免引起其他村民对你的怀疑。
9
+ 以下是几个合适的示例:
10
+ "我昨晚听到东边有些动静,但不确定是什么。"
11
+ "我觉得4号玩家的行为有点反常,大家要多加注意。"
12
+ "根据我的观察,2号和5号之间似乎有些默契。"
13
+ 请按照类似的风格,结合当前游戏局势进行发言:
14
+ """
15
+ VOTE_PROMPT = """{history}
16
+ 你是{name},作为一名平民,你的使命是找出潜伏的狼人。
17
+ 请仔细分析当前游戏局势,选择你认为最可能是狼人的玩家进行投票:
18
+
19
+ 注意观察每个玩家的发言,寻找逻辑矛盾或可疑之处。
20
+ 关注玩家之间的互动,是否有人在刻意包庇或陷害他人。
21
+ 分析投票倾向,是否有玩家在关键时刻改变立场。
22
+ 留意反常行为,如过分激动或过于沉默的玩家。
23
+ 从以下玩家中选择你认为最可能是狼人的人:{choices}
24
+ 请直接返回你要投票的玩家名字:
25
+ """
werewolf/villager/villager_agent.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent_build_sdk.example.werewolf.villager.prompt import DESC_PROMPT, VOTE_PROMPT
2
+ from agent_build_sdk.model.roles import ROLE_VILLAGER
3
+ from agent_build_sdk.model.werewolf_model import AgentResp, AgentReq, STATUS_START, STATUS_WOLF_SPEECH, \
4
+ STATUS_VOTE_RESULT, STATUS_SKILL, STATUS_SKILL_RESULT, STATUS_NIGHT_INFO, STATUS_DAY, STATUS_DISCUSS, STATUS_VOTE, \
5
+ STATUS_RESULT, STATUS_NIGHT
6
+ from agent_build_sdk.utils.logger import logger
7
+ from agent_build_sdk.sdk.role_agent import BasicRoleAgent
8
+ from agent_build_sdk.sdk.agent import format_prompt
9
+
10
+
11
+ class VillagerAgent(BasicRoleAgent):
12
+ """平民角色Agent"""
13
+
14
+ def __init__(self):
15
+ super().__init__(ROLE_VILLAGER)
16
+
17
+ def perceive(self, req=AgentReq):
18
+ if req.status == STATUS_START:
19
+ self.memory.clear()
20
+ self.memory.set_variable("name", req.name)
21
+ self.memory.append_history("主持人:大家好,我们正在玩狼人杀游戏,6人局,包括预言家、女巫、猎人、平民和狼人")
22
+ self.memory.append_history("主持人:你好,你分配到的角色是[平民]")
23
+ if req.status == STATUS_NIGHT:
24
+ self.memory.append_history("主持人:现在进入夜晚,天黑请闭眼")
25
+ if req.status == STATUS_NIGHT_INFO:
26
+ self.memory.append_history(f"主持人:天亮了!昨天晚上的信息是: {req.message}")
27
+ elif req.status == STATUS_DISCUSS: # 发言环节
28
+ if req.name:
29
+ # 其他玩家发言
30
+ self.memory.append_history(req.name + ': ' + req.message)
31
+ else:
32
+ # 主持人发言
33
+ self.memory.append_history('主持人: 现在进入第{}天。'.format(str(req.round)))
34
+ self.memory.append_history('主持人: 每个玩家描述自己的信息。')
35
+ elif req.status == STATUS_VOTE: # 投票环节
36
+ self.memory.append_history(req.name + ': ' + req.message)
37
+ elif req.status == STATUS_VOTE_RESULT: # 投票环节
38
+ out_player = req.name if req.name else req.message
39
+ if out_player:
40
+ self.memory.append_history('主持人: 投票结果是:{}。'.format(out_player))
41
+ else:
42
+ self.memory.append_history('主持人: 无人出局。')
43
+ elif req.status == STATUS_RESULT:
44
+ self.memory.append_history(req.message)
45
+ else:
46
+ raise NotImplementedError
47
+ pass
48
+
49
+ def interact(self, req=AgentReq) -> AgentResp:
50
+ logger.info("spy interact: {}".format(req))
51
+ if req.status == STATUS_DISCUSS:
52
+ prompt = format_prompt(DESC_PROMPT,
53
+ {"name": self.memory.load_variable("name"),
54
+ "word": self.memory.load_variable("word"),
55
+ "history": "\n".join(self.memory.load_history())
56
+ })
57
+ logger.info("prompt:" + prompt)
58
+ result = self.llm_caller(prompt)
59
+ logger.info("spy interact result: {}".format(result))
60
+ return AgentResp(success=True, result=result, errMsg=None)
61
+
62
+ elif req.status == STATUS_VOTE:
63
+ self.memory.append_history('主持人: 到了投票的时候了。每个人,请指向你认为可能是狼人的人。')
64
+ choices = [name for name in req.message.split(",") if name != self.memory.load_variable("name")] # 排除自己
65
+ self.memory.set_variable("choices", choices)
66
+ prompt = format_prompt(VOTE_PROMPT, {"name": self.memory.load_variable("name"),
67
+ "choices": choices,
68
+ "history": "\n".join(self.memory.load_history())
69
+ })
70
+ logger.info("prompt:" + prompt)
71
+ result = self.llm_caller(prompt)
72
+ logger.info("spy interact result: {}".format(result))
73
+ return AgentResp(success=True, result=result, errMsg=None)
74
+ else:
75
+ raise NotImplementedError
76
+ pass
werewolf/witch/prompt.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DESC_PROMPT = """{history}
2
+ 你是{name},你是一名女巫。你的目标是找出狼人,保护村庄。你拥有两瓶药:一瓶解药可以救活一名被狼人杀死的玩家,一瓶毒药可以毒死一名玩家。每种药只能使用一次。
3
+ 目前你的药水状态:解药({'有' if has_antidote else '已用完'}),毒药({'有' if has_poison else '已用完'})。
4
+
5
+ 请根据游戏规则和此前的对话,提供一个自然且合理的描述,确保:
6
+
7
+ 你的描述要真实可信,表现出对村庄的关心和对狼人的警惕。
8
+ 你的发言应当像一个女巫,使用日常的语言表达方式,但可以暗示你有能力救人或杀人。
9
+ 你可以描述你观察到的可疑行为,或分享你对其他玩家的看法。
10
+ 要谨慎发言,避免过早暴露自己的身份,但也可以适当暗示你的能力。
11
+ 以下是几个合适的示例:
12
+ "昨晚我感觉到了一些不寻常的气息,我有办法应对危险。"
13
+ "我觉得4号玩家的行为有点反常,我会密切关注他。"
14
+ "我有能力在关键时刻帮助大家,但我需要谨慎使用这种能力。"
15
+ 请按照类似的风格,结合当前游戏局势进行发言:
16
+ """
17
+
18
+ VOTE_PROMPT = """{history}
19
+ 你是{name},作为一名女巫,你的使命是找出潜伏的狼人。
20
+ 请仔细分析当前游戏局势,选择你认为最可能是狼人的玩家进行投票:
21
+
22
+ 注意观察每个玩家的发言,寻找逻辑矛盾或可疑之处。
23
+ 关注玩家之间的互动,是否有人在刻意包庇或陷害他人。
24
+ 分析投票倾向,是否有玩家在关键时刻改变立场。
25
+ 留意反常行为,如过分激动或过于沉默的玩家。
26
+ 从以下玩家中选择你认为最可能是狼人的人:{choices}
27
+ 请直接返回你要投票的玩家名字:
28
+ """
29
+
30
+ SKILL_PROMPT = """{history}
31
+ 你是{name},作为女巫,你现在可以使用你的技能。
32
+ 今晚{tonight_killed}被狼人杀死了。
33
+
34
+ 你目前拥有的药水:
35
+ - 解药:{'有' if has_antidote else '已用完'}
36
+ - 毒药:{'有' if has_poison else '已用完'}
37
+
38
+ 你可以:
39
+ 1. 使用解药救活{tonight_killed}(如果你还有解药)
40
+ 2. 使用毒药杀死一名玩家(如果你还有毒药)
41
+ 3. 不使用任何药水
42
+
43
+ 请仔细分析当前游戏局势,做出最有利于村民阵营的决定。
44
+ 如果你决定使用解药,请回复"救{tonight_killed}"
45
+ 如果你决定使用毒药,请回复"毒[玩家名]",从以下玩家中选择:{choices}
46
+ 如果你决定不使用任何药水,请回复"不使用"
47
+
48
+ 请直接返回你的决定:
49
+ """
werewolf/witch/witch_agent.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent_build_sdk.model.roles import ROLE_WITCH
2
+ from agent_build_sdk.model.werewolf_model import AgentResp, AgentReq, STATUS_START, STATUS_WOLF_SPEECH, \
3
+ STATUS_VOTE_RESULT, STATUS_SKILL, STATUS_SKILL_RESULT, STATUS_NIGHT_INFO, STATUS_DAY, STATUS_DISCUSS, STATUS_VOTE, \
4
+ STATUS_RESULT, STATUS_NIGHT, STATUS_SKILL
5
+ from agent_build_sdk.utils.logger import logger
6
+ from agent_build_sdk.sdk.role_agent import BasicRoleAgent
7
+ from agent_build_sdk.sdk.agent import format_prompt
8
+ from agent_build_sdk.example.werewolf.witch.prompt import DESC_PROMPT, VOTE_PROMPT, SKILL_PROMPT
9
+
10
+
11
+ class WitchAgent(BasicRoleAgent):
12
+ """女巫角色Agent"""
13
+
14
+ def __init__(self, llm_caller=None, memory=None):
15
+ super().__init__(ROLE_WITCH, llm_caller, memory)
16
+ # 初始化女巫的两瓶药
17
+ self.memory.set_variable("has_poison", True)
18
+ self.memory.set_variable("has_antidote", True)
19
+
20
+ def perceive(self, req=AgentReq):
21
+ if req.status == STATUS_START:
22
+ self.memory.clear()
23
+ self.memory.set_variable("name", req.name)
24
+ # 重置女巫的两瓶药
25
+ self.memory.set_variable("has_poison", True)
26
+ self.memory.set_variable("has_antidote", True)
27
+ self.memory.append_history("主持人:大家好,我们正在玩狼人杀游戏,6人局,包括预言家、女巫、猎人、平民和狼人")
28
+ self.memory.append_history("主持人:你好,你分配到的角色是[女巫]")
29
+ if req.status == STATUS_NIGHT:
30
+ self.memory.append_history("主持人:现在进入夜晚,天黑请闭眼")
31
+ if req.status == STATUS_SKILL_RESULT:
32
+ self.memory.append_history(f"主持人:女巫,你使用技能的结果是{req.message}")
33
+ if req.status == STATUS_NIGHT_INFO:
34
+ self.memory.append_history(f"主持人:天亮了!昨天晚上的信息是: {req.message}")
35
+ elif req.status == STATUS_DISCUSS: # 发言环节
36
+ if req.name:
37
+ # 其他玩家发言
38
+ self.memory.append_history(req.name + ': ' + req.message)
39
+ else:
40
+ # 主持人发言
41
+ self.memory.append_history('主持人: 现在进入第{}天。'.format(str(req.round)))
42
+ self.memory.append_history('主持人: 每个玩家描述自己的信息。')
43
+ elif req.status == STATUS_VOTE: # 投票环节
44
+ self.memory.append_history(req.name + ': ' + req.message)
45
+ elif req.status == STATUS_VOTE_RESULT: # 投票环节
46
+ out_player = req.name if req.name else req.message
47
+ if out_player:
48
+ self.memory.append_history('主持人: 投票结果是:{}。'.format(out_player))
49
+ else:
50
+ self.memory.append_history('主持人: 无人出局。')
51
+ elif req.status == STATUS_RESULT:
52
+ self.memory.append_history(req.message)
53
+ else:
54
+ raise NotImplementedError
55
+
56
+ def interact(self, req=AgentReq) -> AgentResp:
57
+ logger.info("witch interact: {}".format(req))
58
+ if req.status == STATUS_DISCUSS:
59
+ prompt = format_prompt(DESC_PROMPT,
60
+ {"name": self.memory.load_variable("name"),
61
+ "has_poison": self.memory.load_variable("has_poison"),
62
+ "has_antidote": self.memory.load_variable("has_antidote"),
63
+ "history": "\n".join(self.memory.load_history())
64
+ })
65
+ logger.info("prompt:" + prompt)
66
+ result = self.llm_caller(prompt)
67
+ logger.info("witch interact result: {}".format(result))
68
+ return AgentResp(success=True, result=result, errMsg=None)
69
+
70
+ elif req.status == STATUS_VOTE:
71
+ self.memory.append_history('主持人: 到了投票的时候了。每个人,请指向你认为可能是狼人的人。')
72
+ choices = [name for name in req.message.split(",") if name != self.memory.load_variable("name")] # 排除自己
73
+ self.memory.set_variable("choices", choices)
74
+ prompt = format_prompt(VOTE_PROMPT, {"name": self.memory.load_variable("name"),
75
+ "choices": choices,
76
+ "history": "\n".join(self.memory.load_history())
77
+ })
78
+ logger.info("prompt:" + prompt)
79
+ result = self.llm_caller(prompt)
80
+ logger.info("witch interact result: {}".format(result))
81
+ return AgentResp(success=True, result=result, errMsg=None)
82
+
83
+ elif req.status == STATUS_SKILL:
84
+ has_poison = self.memory.load_variable("has_poison")
85
+ has_antidote = self.memory.load_variable("has_antidote")
86
+ tonight_killed = req.name
87
+
88
+ choices = [name for name in req.message.split(",") if name != self.memory.load_variable("name")] # 排除自己
89
+ self.memory.set_variable("choices", choices)
90
+
91
+ prompt = format_prompt(SKILL_PROMPT, {
92
+ "name": self.memory.load_variable("name"),
93
+ "choices": choices,
94
+ "tonight_killed": tonight_killed,
95
+ "has_poison": has_poison,
96
+ "has_antidote": has_antidote,
97
+ "history": "\n".join(self.memory.load_history())
98
+ })
99
+
100
+ logger.info("prompt:" + prompt)
101
+ result = self.llm_caller(prompt)
102
+ logger.info("witch skill result: {}".format(result))
103
+ # 根据结果更新药水状态
104
+ skill_target_person = None
105
+ if result.startswith("救") and has_antidote:
106
+ self.memory.set_variable("has_antidote", False)
107
+ self.memory.append_history(f"女巫使用解药救活了{tonight_killed}")
108
+ skill_target_person = tonight_killed
109
+ elif result.startswith("毒") and has_poison:
110
+ poisoned_player = result[1:].strip()
111
+ self.memory.set_variable("has_poison", False)
112
+ self.memory.append_history(f"女巫使用毒药杀死了{poisoned_player}")
113
+ skill_target_person = poisoned_player
114
+
115
+ return AgentResp(success=True, result=result, skill_target_person=skill_target_person, errMsg=None)
116
+ else:
117
+ raise NotImplementedError
werewolf/wolf/prompt.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DESC_PROMPT = """{history}
2
+ 你是{name},你是一名狼人。你的目标是消灭所有村民,保护自己不被发现。
3
+ 你的狼人队友是:{teammates}
4
+
5
+ 请根据游戏规则和此前的对话,提供一个自然且合理的描述,确保:
6
+
7
+ 你的描述要伪装成村民,不要暴露自己的狼人身份。
8
+ 你的发言应当像一个普通村民或特殊角色,使用日常的语言表达方式。
9
+ 你可以描述虚构的观察或线索,误导其他玩家。
10
+ 可以适当怀疑其他玩家,但不要过度针对自己的狼人队友。
11
+ 以下是几个合适的示例:
12
+ "昨晚我听到东边有些动静,可能是狼人活动的声音。"
13
+ "我觉得4号玩家的行为有点反常,大家要多加注意。"
14
+ "作为一名普通村民,我会尽力帮助大家找出狼人。"
15
+ 请按照类似的风格,结合当前游戏局势进行发言:
16
+ """
17
+
18
+ VOTE_PROMPT = """{history}
19
+ 你是{name},作为一名狼人,你的使命是消灭所有村民。
20
+ 请仔细分析当前游戏局势,选择一个投票策略:
21
+
22
+ 避免投票给你的狼人队友:{teammates}
23
+ 考虑投票给对狼人威胁最大的村民角色(如预言家、女巫)。
24
+ 如果有玩家怀疑你或你的队友,可以考虑投票给他转移注意力。
25
+ 如果大多数人都在投某个玩家,你可以跟随大众以避免引起怀疑。
26
+ 从以下玩家中选择你要投票的人:{choices}
27
+ 请直接返回你要投票的玩家名字:
28
+ """
29
+
30
+ WOLF_SPEECH_PROMPT = """{history}
31
+ 你是{name},现在是狼人之间的交流时间。你可以与你的狼人队友{teammates}讨论今晚要击杀谁。
32
+
33
+ 请考虑以下因素:
34
+ 1. 哪个玩家对狼人阵营威胁最大(如预言家、女巫)
35
+ 2. 是否有人已经怀疑到你或你的队友
36
+ 3. 击杀哪个玩家可以制造最大的混乱
37
+ 4. 你的队友之前有没有提出建议
38
+
39
+ 请提出你的建议或回应队友的建议:
40
+ """
41
+
42
+ KILL_PROMPT = """{history}
43
+ 你是{name},作为狼人,现在需要选择今晚要击杀的目标。
44
+
45
+ 请仔细分析当前游戏局势,选择一个最佳的击杀目标:
46
+
47
+ 1. 优先考虑击杀对狼人威胁最大的角色(如预言家、女巫)
48
+ 2. 如果有人怀疑你或你的队友,可以考虑击杀他
49
+ 3. 避免击杀看起来像狼人的玩家,以免引起村民的混淆
50
+ 4. 考虑游戏的整体战略,选择最有利于狼人获胜的目标
51
+
52
+ 从以下玩家中选择你要击杀的人:{choices}
53
+ 请直接返回你要击杀的玩家名字:
54
+ """
werewolf/wolf/wolf_agent.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent_build_sdk.model.roles import ROLE_WOLF
2
+ from agent_build_sdk.model.werewolf_model import AgentResp, AgentReq, STATUS_START, STATUS_WOLF_SPEECH, \
3
+ STATUS_VOTE_RESULT, STATUS_SKILL, STATUS_SKILL_RESULT, STATUS_NIGHT_INFO, STATUS_DAY, STATUS_DISCUSS, STATUS_VOTE, \
4
+ STATUS_RESULT, STATUS_NIGHT, STATUS_SKILL
5
+ from agent_build_sdk.utils.logger import logger
6
+ from agent_build_sdk.sdk.role_agent import BasicRoleAgent
7
+ from agent_build_sdk.sdk.agent import format_prompt
8
+ from agent_build_sdk.example.werewolf.wolf.prompt import DESC_PROMPT, VOTE_PROMPT, KILL_PROMPT, WOLF_SPEECH_PROMPT
9
+
10
+
11
+ class WolfAgent(BasicRoleAgent):
12
+ """狼人角色Agent"""
13
+
14
+ def __init__(self, llm_caller=None, memory=None):
15
+ super().__init__(ROLE_WOLF, llm_caller, memory)
16
+ self.memory.set_variable("teammates", []) # 存储队友信息
17
+
18
+ def perceive(self, req=AgentReq):
19
+ if req.status == STATUS_START:
20
+ self.memory.clear()
21
+ self.memory.set_variable("name", req.name)
22
+ self.memory.set_variable("teammates", []) # 重置队友信息
23
+ self.memory.append_history("主持人:大家好,我们正在玩狼人杀游戏,6人局,包括预言家、女巫、猎人、平民和狼人")
24
+ self.memory.append_history("主持人:你好,你分配到的角色是[狼人]")
25
+ if req.message: # 如果有队友信息
26
+ teammates = req.message.split(",")
27
+ self.memory.set_variable("teammates", teammates)
28
+ self.memory.append_history(f"主持人:你的狼人队友是: {req.message}")
29
+ if req.status == STATUS_NIGHT:
30
+ self.memory.append_history("主持人:现在进入夜晚,天黑请闭眼")
31
+ if req.status == STATUS_WOLF_SPEECH:
32
+ # 狼人之间的交流
33
+ if req.name:
34
+ self.memory.append_history(f"狼人{req.name}说: {req.message}")
35
+ else:
36
+ self.memory.append_history("主持人:狼人请睁眼,狼人请互相确认身份,并选择要击杀的对象")
37
+ if req.status == STATUS_SKILL_RESULT:
38
+ self.memory.append_history(f"主持人:狼人请今晚选择击杀的目标是:{req.name}")
39
+ if req.status == STATUS_NIGHT_INFO:
40
+ self.memory.append_history(f"主持人:天亮了!昨天晚上的信息是: {req.message}")
41
+ elif req.status == STATUS_DISCUSS: # 发言环节
42
+ if req.name:
43
+ # 其他玩家发言
44
+ self.memory.append_history(req.name + ': ' + req.message)
45
+ else:
46
+ # 主持人发言
47
+ self.memory.append_history('主持人: 现在进入第{}天。'.format(str(req.round)))
48
+ self.memory.append_history('主持人: 每个玩家描述自己的信息。')
49
+ elif req.status == STATUS_VOTE: # 投票环节
50
+ self.memory.append_history(req.name + ': ' + req.message)
51
+ elif req.status == STATUS_VOTE_RESULT: # 投票环节
52
+ out_player = req.name if req.name else req.message
53
+ if out_player:
54
+ self.memory.append_history('主持人: 投票结果是:{}。'.format(out_player))
55
+ else:
56
+ self.memory.append_history('主持人: 无人出局。')
57
+ elif req.status == STATUS_RESULT:
58
+ self.memory.append_history(req.message)
59
+ else:
60
+ raise NotImplementedError
61
+
62
+ def interact(self, req=AgentReq) -> AgentResp:
63
+ logger.info("wolf interact: {}".format(req))
64
+ if req.status == STATUS_DISCUSS:
65
+ teammates = self.memory.load_variable("teammates")
66
+ prompt = format_prompt(DESC_PROMPT,
67
+ {"name": self.memory.load_variable("name"),
68
+ "teammates": teammates,
69
+ "history": "\n".join(self.memory.load_history())
70
+ })
71
+ logger.info("prompt:" + prompt)
72
+ result = self.llm_caller(prompt)
73
+ logger.info("wolf interact result: {}".format(result))
74
+ return AgentResp(success=True, result=result, errMsg=None)
75
+
76
+ elif req.status == STATUS_VOTE:
77
+ self.memory.append_history('主持人: 到了投票的时候了。每个人,请指向你认为可能是狼人的人。')
78
+ teammates = self.memory.load_variable("teammates")
79
+ choices = [name for name in req.message.split(",")
80
+ if name != self.memory.load_variable("name") and name not in teammates] # 排除自己和队友
81
+ self.memory.set_variable("choices", choices)
82
+ prompt = format_prompt(VOTE_PROMPT, {"name": self.memory.load_variable("name"),
83
+ "teammates": teammates,
84
+ "choices": choices,
85
+ "history": "\n".join(self.memory.load_history())
86
+ })
87
+ logger.info("prompt:" + prompt)
88
+ result = self.llm_caller(prompt)
89
+ logger.info("wolf interact result: {}".format(result))
90
+ return AgentResp(success=True, result=result, errMsg=None)
91
+
92
+ elif req.status == STATUS_WOLF_SPEECH:
93
+ teammates = self.memory.load_variable("teammates")
94
+ prompt = format_prompt(WOLF_SPEECH_PROMPT, {
95
+ "name": self.memory.load_variable("name"),
96
+ "teammates": teammates,
97
+ "history": "\n".join(self.memory.load_history())
98
+ })
99
+ logger.info("prompt:" + prompt)
100
+ result = self.llm_caller(prompt)
101
+ logger.info("wolf speech result: {}".format(result))
102
+ return AgentResp(success=True, result=result, errMsg=None)
103
+
104
+ elif req.status == STATUS_SKILL:
105
+ teammates = self.memory.load_variable("teammates")
106
+ choices = [name for name in req.message.split(",")
107
+ if name != self.memory.load_variable("name") and name not in teammates] # 排除自己和队友
108
+ self.memory.set_variable("choices", choices)
109
+ prompt = format_prompt(KILL_PROMPT, {
110
+ "name": self.memory.load_variable("name"),
111
+ "choices": choices,
112
+ "history": "\n".join(self.memory.load_history())
113
+ })
114
+ logger.info("prompt:" + prompt)
115
+ result = self.llm_caller(prompt)
116
+ logger.info("wolf kill result: {}".format(result))
117
+ return AgentResp(success=True, result=result, skill_target_player=result, serrMsg=None)
118
+ else:
119
+ raise NotImplementedError