Heim >Backend-Entwicklung >Python-Tutorial >Interaktiver Projektbericht mit Jira und LLM
Für alle Projekte, an denen ich gearbeitet habe, habe ich eine Art Projektmanagementsystem verwendet, in dem der Projektumfang als eine Liste von Aufgaben (Tickets) definiert wurde und der Fortschritt durch Ändern des Aufgabenstatus gemeldet wurde.
Während solche Projektmanagementsysteme verschiedene Dashboards und Berichte bieten, ist die Interpretation einer langen Liste von Aufgaben mit kryptischen Titeln, die von Ingenieuren erstellt wurden, nicht trivial. Um Transparenz für Projektsponsoren und Kunden zu schaffen, musste ich manuell einen Projektbericht erstellen und dann entsprechende Fragen beantworten.
Was wäre, wenn wir stattdessen LLM um Hilfe bitten würden? Die Idee ist einfach: Alle Projektaufgaben abrufen und an LLM weiterleiten, um den Bericht anzufordern. Starten Sie dann einen Chat, in dem weitere Fragen gestellt werden können.
Wir werden Jira für dieses Experiment verwenden, da es ein beliebtes Tool mit einer benutzerfreundlichen REST-API ist. Das Beispielprojekt, für das wir den Bericht erstellen werden, ist sehr technisch – es geht darum, ein Build-Skript zu erstellen, das erkennen kann, was der Code verwendet, und die erforderlichen Anweisungen für das Build-System generieren kann. Ein solches Projekt wird sicherlich technische Aufgaben mit kryptischen Titeln haben.
Beginnen wir mit dem Abrufen von Aufgaben. Das Projekt im Beispiel-Setup wird als einzelnes übergeordnetes Ticket (ein Epic) mit einer Liste untergeordneter Tickets (Aufgaben) dargestellt. Für jede Aufgabe rufen wir den vollständigen Verlauf ab, um zu sehen, wie sich der Ticketstatus im Laufe der Zeit ändert. Mit dem Jira-Client von Python ist die Implementierung einfach. Beachten Sie, dass in der Jira-Nomenklatur der Begriff Issue anstelle von Ticket verwendet wird, was sich im Code widerspiegelt.
jira = JIRA(server=os.environ["JIRA_SERVER"], basic_auth=(os.environ["JIRA_USER"], os.environ["JIRA_TOKEN"])) def fetch_issues(epic_key): issues = [] print("Loading epic data...", end="", flush=True) issues.append(jira.issue(epic_key)) print("done") print("Loading tasks...", end="", flush=True) child_issues = jira.search_issues(f"parent = {epic_key}") for issue in child_issues: issues.append(jira.issue(issue.key, expand="changelog")) print("done") return issues
Da das Abrufen aller Tickets mit Verlauf eine Weile dauert, ist es praktisch, diese Daten für weitere Experimente lokal zu speichern. Beim Spielen mit der Implementierung habe ich die folgenden Funktionen verwendet, um Aufgaben in einer Datei zu speichern und aus einer Datei zu laden:
def save_issues(filename, issues): with open(filename, "x") as file: file.write("[") file.write(",".join( json.dumps(issue.raw) for issue in issues)) file.write("]") def load_issues(filename): with open(filename, "r") as file: data = json.load(file) return [Issue(jira._options, jira._session, raw=raw_issue) for raw_issue in data]
Der nächste Schritt besteht darin, Daten für LLM vorzubereiten. Rohe Jira-Daten im JSON-Format sind ziemlich ausführlich, wir benötigen nicht alle diese zusätzlichen Felder. Lassen Sie uns grundlegende Informationen extrahieren: Betreff, Beschreibung, Typ, Status und Erstellungsdatum. Aus dem Verlauf extrahieren wir nur Ticketstatusänderungen zusammen mit Datum und Autor und ignorieren Änderungen in anderen Feldern.
Alle diese Informationen werden als Klartext gespeichert. Ich habe Leute gesehen, die JSON oder XML als LLM-Eingabe verwendet haben, aber meiner Beobachtung nach sind LLMs sehr gut darin, reine Textdaten zu interpretieren. Außerdem muss ich mir bei diesem Ansatz keine Gedanken über die JSON- oder XML-kompatible Formatierung von Textfeldern machen. Die einzige Verarbeitung, die ich vornehme, besteht darin, leere Zeilen aus der Beschreibung zu entfernen. Der Hauptgrund besteht darin, mir die Anzeige der Ergebnisse zu erleichtern.
def strip_empty_lines(s): return "".join(line for line in (s or "").splitlines() if line.strip()) def issue_to_str(issue): return f""" {issue.fields.issuetype}: {issue.key} Summary: {issue.fields.summary} Description: {strip_empty_lines(issue.fields.description)} Type: {issue.fields.issuetype} Status: {issue.fields.status} Created: {issue.fields.created} Priority: {issue.fields.priority} """ def changelog_to_str(changelog, changeitem): return f""" Author: {changelog.author.displayName} Date: {changelog.created} Status change from: {changeitem.fromString} to: {changeitem.toString} """ def history_to_str(issue): if issue.changelog is None or issue.changelog.total == 0: return "" history_description = "" for changelog in issue.changelog.histories: try: statuschange = next(filter(lambda i: i.field == "status", changelog.items)) history_description += changelog_to_str(changelog, statuschange) except StopIteration: pass return history_description #this function assumes the first issue is an epic followed by tasks. def describe_issues(issues): description = "Project details:" description += issue_to_str(issues[0]) description += "\nProject tasks:" for issue in issues[1:]: description += "\n" + issue_to_str(issue) description += f"History of changes for task {issue.key}:" description += history_to_str(issue) return description
Das Epos, das ich für dieses Experiment verwende, hat 30 Aufgaben, deren Verlauf zwischen 1 und 15 Statusänderungen aufweist. Ich werde nicht die vollständige Ausgabe der Funktion „describe_issues“ zitieren, aber um Ihnen eine Vorstellung davon zu geben, wie sie aussieht, hier ein kurzer Auszug:
Project details: Epic: TKT-642 Summary: Create universal build script Description: Type: Epic Status: In Development Created: 2024-05-24T10:48:33.050+0200 Priority: P4 - Low Project tasks: Task: TKT-805 Summary: add test reporting for e2e tests Description: Type: Task Status: In Progress Created: 2024-09-06T09:56:33.919+0200 Priority: P4 - Low History of changes for task TKT-805: Author: Jane Doe Date: 2024-09-06T10:04:15.325+0200 Status change from: To Do to: In Progress Task: TKT-801 Summary: Sonar detection Description: * add sonar config file detection * Type: Task Status: In Progress Created: 2024-08-30T13:57:44.364+0200 Priority: P4 - Low History of changes for task TKT-801: Author: Jane Doe Date: 2024-08-30T13:57:58.450+0200 Status change from: To Do to: In Progress Task: TKT-799 Summary: Add check_tests step Description: Type: Task Status: Review Created: 2024-08-29T18:33:52.268+0200 Priority: P4 - Low History of changes for task TKT-799: Author: Jane Doe Date: 2024-08-29T18:40:35.305+0200 Status change from: In Progress to: Review Author: Jane Doe Date: 2024-08-29T18:33:57.095+0200 Status change from: To Do to: In Progress
Die Eingabeaufforderung, die wir verwenden werden, besteht aus zwei Teilen. Zunächst erhalten Sie eine Anweisung zum Erstellen eines Berichts, in der detailliert beschrieben wird, welche spezifischen Informationen in den Bericht aufgenommen werden sollen. Anschließend fügen wir die in den vorherigen Absätzen vorbereiteten Ticketinformationen ein. LLMs neigen dazu, ausführliche Antworten zu geben, daher bitten wir Sie ausdrücklich, keine zusätzlichen Erklärungen hinzuzufügen. Da das Experiment im Terminal durchgeführt wird, bitten wir auch darum, die Antwort terminalfreundlich zu gestalten.
def create_prompt(isses_description): return f""" Using below information from jira generate executive report that focuses on what was done and what is remaining. Provide project progress information. Point out problematic tasks and what may be wrong. Use status change history to point out tasks that were worked on for too long or have been reopened many times. Check if you can detect other problems from tasks or their history. Provide only text content that can be displayed on terminal, without any additional explanation or markdown. {isses_description} """
Das LLM, das ich für dieses Experiment verwende, ist Claude 3.5 Sonnet von Anthropic. Zusätzlich zum Senden der Aufforderungsnachricht geben wir auch die Identität an. Identität könnte einfach als weitere Zeile am Anfang der Eingabeaufforderung hinzugefügt werden, aber da geplant ist, Fragen zu stellen (einen interaktiven Chat zu erstellen), empfiehlt Claudes Dokumentation, Identität in einem solchen Szenario als separaten Systemparameter festzulegen.
def send_messages(messages): client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_KEY"]) identity = "You are a seasoned IT program manager. You have very good communication skills, your answers are concise and focus on key insights." message = client.messages.create( system=identity, max_tokens=2048, messages=messages, model="claude-3-5-sonnet-20240620" ) return message.content[0].text def generate_report(prompt): messages=[ { "role": "user", "content": prompt }] return send_messages(messages)
Lass uns das zusammensetzen und ausführen:
if __name__=="__main__": issues = fetch_issues('TKT-642') descrption = describe_issues(issues) prompt = create_prompt(description) report = generate_report(prompt) print(report)
Unten ist der vollständige Bericht, den ich von Claude erhalten habe:
Executive Report: Universal Build Script Project (TKT-642)
Projektfortschritt:
- 11 von 24 Aufgaben sind erledigt (45,8%)
- 5 Aufgaben sind in Bearbeitung oder werden überprüft (20,8 %)
- 8 Aufgaben müssen noch gestartet werden (33,3 %)
Wichtige Erfolge:
- Prototyp-Jinja-Vorlage für Builder erstellt
- Konfigurationserweiterung und -validierung implementiert
- Schritt zur Ausführung von Komponententests hinzugefügt
- Integrierte Unterstützung für Sonar-Scanning
- Bild zum Erstellen von Konfigurations- und Tech-Skripten erstellt
In Bearbeitung:
- Testberichte für E2E-Tests hinzufügen
- Implementierung von Filterlogik für Umgebungen und Sonarerkennung
- Entwickeln einer Entwicklerdokumentation
Problembereiche:
- Task TKT-734 (Add config extension) went through multiple status changes, indicating potential issues or complexity.
- Task TKT-697 (Add support for sonar scanning) has been reopened multiple times, suggesting implementation challenges.
- Task TKT-715 (Create developer documentation) has been in progress for an extended period without completion.
Upcoming Work:
- Integration of the build system into various services (authentication, database-api, shopping-cart, reporting, localization)
- Adding support for monorepos and custom jobs
- Creating user documentation
Recommendations:
- Review the implementation of config extension and sonar scanning to address recurring issues.
- Prioritize the completion of developer documentation to support team adoption.
- Begin planning for the integration of the build system into remaining services.
- Consider reassessing the priority of tasks that have remained in the "To Do" state for an extended period.
Overall, the project is making steady progress, with nearly half of the tasks completed. However, attention should be given to resolving recurring issues and completing in-progress tasks to maintain momentum.
The result is quite good. It did miscount tickets - in various runs I did it gave me a different number, but never a correct number of 30. Well, LLMs are known for not being able to count r's in the word strawberry. But the summary is correct, recommendations are also reasonable.
Now let's create an interactive session and ask some questions. We'll start with a pre-defined question which is the original prompt we used to generate the report. Then we will read the user's input and attach it to messages. Each response, along with the report is also recorded in the messages chain.
def interactive_session(prompt): messages = [] user_input = prompt while user_input != "exit": messages.append({ "role" : "user", "content" : user_input }) response = send_messages(messages) print(response) messages.append({ "role" : "assistant", "content" : response }) user_input = input("QUESTION: ") return messages
To run this, just replace generate_report in the main section of the script with interactive_session. Below is a recording of an example session I did. I omitted from the quote the first response which just prints out the report.
QUESTION: how many engineers the team counts?
Based on the information provided in the task histories, I can identify at least three distinct engineers working on this project:
- John Smith
- Jane Doe
- Mike Carpenter
These three names appear frequently in the status change histories for various tasks. However, it's important to note that this may not represent the full team size. There could be other team members who haven't made changes recorded in these specific task histories, or who are involved in the project in other capacities not reflected in this data.
To get an accurate count of the team size, you would need additional information beyond what's provided in these task histories.
QUESTION: is unit test execution task done yet?
Yes, the unit test execution task is completed. Specifically, task TKT-700 with the summary "Add unit tests execution step" is marked as Done. Here's the relevant information:
Task: TKT-700
Summary: Add unit tests execution step
Status: DoneThe history of changes for this task shows that it was moved to "Done" status on 2024-08-02, after going through the typical workflow stages (To Do -> In Progress -> Review -> PREPROD VERIFICATION -> READY FOR PRODUCTION -> Done).
QUESTION: does the scope include running some sort of static code analysis tool?
Yes, the project scope includes running static code analysis. Specifically, there's a task for implementing Sonar scanning, which is a popular static code analysis tool. Here are the details:
Task: TKT-697
Summary: Add support for sonar scanning
Status: DoneThis task was completed and moved to "Done" status on 2024-09-02. The implementation of Sonar scanning indicates that static code analysis is part of the universal build script project.
Additionally, there's another related task that's currently in progress:
Task: TKT-801
Summary: Sonar detection
Status: In ProgressThis task mentions "sonar detection" in its summary, which further confirms that Sonar (a static analysis tool) is being integrated into the build process.
These tasks demonstrate that static code analysis, particularly using Sonar, is included in the project scope and has been largely implemented.
QUESTION: what are the 3 biggest risks of the project?
Based on the provided information, the three biggest risks for this project appear to be:
整合延迟:
将构建系统集成到各种服务(本地化、报告、购物车、身份验证、数据库 API)的多项任务仍处于“待办事项”状态。这带来了跨不同服务广泛采用通用构建脚本的延迟风险。未能集成所有预期服务可能会限制项目的整体影响和价值。文档滞后:
创建开发人员文档 (TKT-715) 的任务在长时间处于“待办事项”状态后,最近才转到“进行中”。此外,用户文档任务 (TKT-714) 仍处于“待办事项”状态。文档创建方面的滞后可能会阻碍新构建系统的采用、正确使用和维护。由于缺乏明确的指导,它可能会导致滥用、效率低下或拒绝采用。实施的复杂性:
多项任务,特别是与声纳扫描 (TKT-697) 和配置扩展 (TKT-734) 相关的任务,已显示“进行中”和“审核”之间的多个状态变化。这种模式表明实施过程中存在潜在的技术挑战或不确定性。如果不妥善解决,这些复杂性可能会在未来导致错误、性能问题或维护困难。如果管理和缓解不当,这些风险可能会影响项目的时间表、采用率和整体成功。
这真是出奇的好。我确实喜欢法学硕士除了提示数据之外还使用通用知识,因此它能够回答有关“静态代码分析工具”的问题,即使没有票证数据提到这些术语。答案有点过于冗长,需要对提示进行更多实验 - 可能向每个用户的查询附加说明将有助于形成更好的答案。
像误算票这样的问题应该很容易解决,我们可以计算基本统计数据并将其包含在提示本身中。
Das obige ist der detaillierte Inhalt vonInteraktiver Projektbericht mit Jira und LLM. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!